Coverage Report

Created: 2026-03-15 06:38

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
0
#define colorSpaceRecursionLimit 8
30
31
32
//------------------------------------------------------------------------
33
34
0
static inline GfxColorComp clip01(GfxColorComp x) {
35
0
  return (x < 0) ? 0 : (x > gfxColorComp1) ? gfxColorComp1 : x;
36
0
}
37
38
0
static inline double clip01(double x) {
39
0
  return (x < 0) ? 0 : (x > 1) ? 1 : x;
40
0
}
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
0
          ((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
0
GfxColorSpace::GfxColorSpace() {
100
0
  overprintMask = 0x0f;
101
0
  defaultColorSpace = gFalse;
102
0
}
103
104
0
GfxColorSpace::~GfxColorSpace() {
105
0
}
106
107
GfxColorSpace *GfxColorSpace::parse(Object *csObj,
108
0
            int recursion) {
109
0
  GfxColorSpace *cs;
110
0
  Object obj1;
111
112
0
  if (recursion > colorSpaceRecursionLimit) {
113
0
    error(errSyntaxError, -1, "Loop detected in color space objects");
114
0
    return NULL;
115
0
  }
116
0
  cs = NULL;
117
0
  if (csObj->isName()) {
118
0
    if (csObj->isName("DeviceGray") || csObj->isName("G")) {
119
0
      cs = GfxColorSpace::create(csDeviceGray);
120
0
    } else if (csObj->isName("DeviceRGB") || csObj->isName("RGB")) {
121
0
      cs = GfxColorSpace::create(csDeviceRGB);
122
0
    } else if (csObj->isName("DeviceCMYK") || csObj->isName("CMYK")) {
123
0
      cs = GfxColorSpace::create(csDeviceCMYK);
124
0
    } else if (csObj->isName("Pattern")) {
125
0
      cs = new GfxPatternColorSpace(NULL);
126
0
    } else {
127
0
      error(errSyntaxError, -1, "Bad color space '{0:s}'", csObj->getName());
128
0
    }
129
0
  } else if (csObj->isArray() && csObj->arrayGetLength() > 0) {
130
0
    csObj->arrayGet(0, &obj1);
131
0
    if (obj1.isName("DeviceGray") || obj1.isName("G")) {
132
0
      cs = GfxColorSpace::create(csDeviceGray);
133
0
    } else if (obj1.isName("DeviceRGB") || obj1.isName("RGB")) {
134
0
      cs = GfxColorSpace::create(csDeviceRGB);
135
0
    } else if (obj1.isName("DeviceCMYK") || obj1.isName("CMYK")) {
136
0
      cs = GfxColorSpace::create(csDeviceCMYK);
137
0
    } else if (obj1.isName("CalGray")) {
138
0
      cs = GfxCalGrayColorSpace::parse(csObj->getArray(), recursion);
139
0
    } else if (obj1.isName("CalRGB")) {
140
0
      cs = GfxCalRGBColorSpace::parse(csObj->getArray(), recursion);
141
0
    } else if (obj1.isName("Lab")) {
142
0
      cs = GfxLabColorSpace::parse(csObj->getArray(), recursion);
143
0
    } else if (obj1.isName("ICCBased")) {
144
0
      cs = GfxICCBasedColorSpace::parse(csObj->getArray(),
145
0
          recursion);
146
0
    } else if (obj1.isName("Indexed") || obj1.isName("I")) {
147
0
      cs = GfxIndexedColorSpace::parse(csObj->getArray(),
148
0
               recursion);
149
0
    } else if (obj1.isName("Separation")) {
150
0
      cs = GfxSeparationColorSpace::parse(csObj->getArray(),
151
0
            recursion);
152
0
    } else if (obj1.isName("DeviceN")) {
153
0
      cs = GfxDeviceNColorSpace::parse(csObj->getArray(),
154
0
               recursion);
155
0
    } else if (obj1.isName("Pattern")) {
156
0
      cs = GfxPatternColorSpace::parse(csObj->getArray(),
157
0
               recursion);
158
0
    } else {
159
0
      error(errSyntaxError, -1, "Bad color space");
160
0
    }
161
0
    obj1.free();
162
0
  } else {
163
0
    error(errSyntaxError, -1, "Bad color space - expected name or array");
164
0
  }
165
0
  return cs;
166
0
}
167
168
0
GfxColorSpace *GfxColorSpace::create(GfxColorSpaceMode mode) {
169
0
  GfxColorSpace *cs;
170
171
0
  cs = NULL;
172
0
  if (mode == csDeviceGray) {
173
0
    cs = new GfxDeviceGrayColorSpace();
174
0
  } else if (mode == csDeviceRGB) {
175
0
    cs = new GfxDeviceRGBColorSpace();
176
0
  } else if (mode == csDeviceCMYK) {
177
0
    cs = new GfxDeviceCMYKColorSpace();
178
0
  }
179
0
  return cs;
180
0
}
181
182
void GfxColorSpace::getDefaultRanges(double *decodeLow, double *decodeRange,
183
0
             int maxImgPixel) {
184
0
  int i;
185
186
0
  for (i = 0; i < getNComps(); ++i) {
187
0
    decodeLow[i] = 0;
188
0
    decodeRange[i] = 1;
189
0
  }
190
0
}
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
0
GfxDeviceGrayColorSpace::GfxDeviceGrayColorSpace() {
205
0
}
206
207
GfxDeviceGrayColorSpace::~GfxDeviceGrayColorSpace() {
208
}
209
210
0
GfxColorSpace *GfxDeviceGrayColorSpace::copy() {
211
0
  GfxDeviceGrayColorSpace *cs;
212
213
0
  cs = new GfxDeviceGrayColorSpace();
214
0
  return cs;
215
0
}
216
217
218
void GfxDeviceGrayColorSpace::getGray(GfxColor *color, GfxGray *gray,
219
0
              GfxRenderingIntent ri) {
220
0
  *gray = clip01(color->c[0]);
221
0
}
222
223
void GfxDeviceGrayColorSpace::getRGB(GfxColor *color, GfxRGB *rgb,
224
0
             GfxRenderingIntent ri) {
225
0
  rgb->r = rgb->g = rgb->b = clip01(color->c[0]);
226
0
}
227
228
void GfxDeviceGrayColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk,
229
0
              GfxRenderingIntent ri) {
230
0
  cmyk->c = cmyk->m = cmyk->y = 0;
231
0
  cmyk->k = clip01(gfxColorComp1 - color->c[0]);
232
0
}
233
234
235
236
0
void GfxDeviceGrayColorSpace::getDefaultColor(GfxColor *color) {
237
0
  color->c[0] = 0;
238
0
}
239
240
//------------------------------------------------------------------------
241
// GfxCalGrayColorSpace
242
//------------------------------------------------------------------------
243
244
0
GfxCalGrayColorSpace::GfxCalGrayColorSpace() {
245
0
  whiteX = whiteY = whiteZ = 1;
246
0
  blackX = blackY = blackZ = 0;
247
0
  gamma = 1;
248
0
}
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
0
GfxColorSpace *GfxCalGrayColorSpace::parse(Array *arr, int recursion) {
269
0
  GfxCalGrayColorSpace *cs;
270
0
  Object obj1, obj2, obj3;
271
272
0
  if (arr->getLength() < 2) {
273
0
    error(errSyntaxError, -1, "Bad CalGray color space");
274
0
    return NULL;
275
0
  }
276
0
  arr->get(1, &obj1);
277
0
  if (!obj1.isDict()) {
278
0
    error(errSyntaxError, -1, "Bad CalGray color space");
279
0
    obj1.free();
280
0
    return NULL;
281
0
  }
282
0
  cs = new GfxCalGrayColorSpace();
283
0
  if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
284
0
      obj2.arrayGetLength() == 3) {
285
0
    obj2.arrayGet(0, &obj3);
286
0
    cs->whiteX = obj3.getNum();
287
0
    obj3.free();
288
0
    obj2.arrayGet(1, &obj3);
289
0
    cs->whiteY = obj3.getNum();
290
0
    obj3.free();
291
0
    obj2.arrayGet(2, &obj3);
292
0
    cs->whiteZ = obj3.getNum();
293
0
    obj3.free();
294
0
  }
295
0
  obj2.free();
296
0
  if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
297
0
      obj2.arrayGetLength() == 3) {
298
0
    obj2.arrayGet(0, &obj3);
299
0
    cs->blackX = obj3.getNum();
300
0
    obj3.free();
301
0
    obj2.arrayGet(1, &obj3);
302
0
    cs->blackY = obj3.getNum();
303
0
    obj3.free();
304
0
    obj2.arrayGet(2, &obj3);
305
0
    cs->blackZ = obj3.getNum();
306
0
    obj3.free();
307
0
  }
308
0
  obj2.free();
309
0
  if (obj1.dictLookup("Gamma", &obj2)->isNum()) {
310
0
    cs->gamma = obj2.getNum();
311
0
  }
312
0
  obj2.free();
313
0
  obj1.free();
314
0
  return cs;
315
0
}
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
0
          GfxRenderingIntent ri) {
324
0
  rgb->r = rgb->g = rgb->b = clip01(color->c[0]);
325
0
}
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
0
void GfxCalGrayColorSpace::getDefaultColor(GfxColor *color) {
336
0
  color->c[0] = 0;
337
0
}
338
339
//------------------------------------------------------------------------
340
// GfxDeviceRGBColorSpace
341
//------------------------------------------------------------------------
342
343
0
GfxDeviceRGBColorSpace::GfxDeviceRGBColorSpace() {
344
0
}
345
346
GfxDeviceRGBColorSpace::~GfxDeviceRGBColorSpace() {
347
}
348
349
0
GfxColorSpace *GfxDeviceRGBColorSpace::copy() {
350
0
  GfxDeviceRGBColorSpace *cs;
351
352
0
  cs = new GfxDeviceRGBColorSpace();
353
0
  return cs;
354
0
}
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
0
            GfxRenderingIntent ri) {
366
0
  rgb->r = clip01(color->c[0]);
367
0
  rgb->g = clip01(color->c[1]);
368
0
  rgb->b = clip01(color->c[2]);
369
0
}
370
371
void GfxDeviceRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk,
372
0
             GfxRenderingIntent ri) {
373
0
  GfxColorComp c, m, y, k;
374
375
0
  c = clip01(gfxColorComp1 - color->c[0]);
376
0
  m = clip01(gfxColorComp1 - color->c[1]);
377
0
  y = clip01(gfxColorComp1 - color->c[2]);
378
0
  k = c;
379
0
  if (m < k) {
380
0
    k = m;
381
0
  }
382
0
  if (y < k) {
383
0
    k = y;
384
0
  }
385
0
  cmyk->c = c - k;
386
0
  cmyk->m = m - k;
387
0
  cmyk->y = y - k;
388
0
  cmyk->k = k;
389
0
}
390
391
392
393
0
void GfxDeviceRGBColorSpace::getDefaultColor(GfxColor *color) {
394
0
  color->c[0] = 0;
395
0
  color->c[1] = 0;
396
0
  color->c[2] = 0;
397
0
}
398
399
//------------------------------------------------------------------------
400
// GfxCalRGBColorSpace
401
//------------------------------------------------------------------------
402
403
0
GfxCalRGBColorSpace::GfxCalRGBColorSpace() {
404
0
  whiteX = whiteY = whiteZ = 1;
405
0
  blackX = blackY = blackZ = 0;
406
0
  gammaR = gammaG = gammaB = 1;
407
0
  mat[0] = 1; mat[1] = 0; mat[2] = 0;
408
0
  mat[3] = 0; mat[4] = 1; mat[5] = 0;
409
0
  mat[6] = 0; mat[7] = 0; mat[8] = 1;
410
0
}
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
0
GfxColorSpace *GfxCalRGBColorSpace::parse(Array *arr, int recursion) {
436
0
  GfxCalRGBColorSpace *cs;
437
0
  Object obj1, obj2, obj3;
438
0
  int i;
439
440
0
  if (arr->getLength() < 2) {
441
0
    error(errSyntaxError, -1, "Bad CalRGB color space");
442
0
    return NULL;
443
0
  }
444
0
  arr->get(1, &obj1);
445
0
  if (!obj1.isDict()) {
446
0
    error(errSyntaxError, -1, "Bad CalRGB color space");
447
0
    obj1.free();
448
0
    return NULL;
449
0
  }
450
0
  cs = new GfxCalRGBColorSpace();
451
0
  if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
452
0
      obj2.arrayGetLength() == 3) {
453
0
    obj2.arrayGet(0, &obj3);
454
0
    cs->whiteX = obj3.getNum();
455
0
    obj3.free();
456
0
    obj2.arrayGet(1, &obj3);
457
0
    cs->whiteY = obj3.getNum();
458
0
    obj3.free();
459
0
    obj2.arrayGet(2, &obj3);
460
0
    cs->whiteZ = obj3.getNum();
461
0
    obj3.free();
462
0
  }
463
0
  obj2.free();
464
0
  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
0
  obj2.free();
477
0
  if (obj1.dictLookup("Gamma", &obj2)->isArray() &&
478
0
      obj2.arrayGetLength() == 3) {
479
0
    obj2.arrayGet(0, &obj3);
480
0
    cs->gammaR = obj3.getNum();
481
0
    obj3.free();
482
0
    obj2.arrayGet(1, &obj3);
483
0
    cs->gammaG = obj3.getNum();
484
0
    obj3.free();
485
0
    obj2.arrayGet(2, &obj3);
486
0
    cs->gammaB = obj3.getNum();
487
0
    obj3.free();
488
0
  }
489
0
  obj2.free();
490
0
  if (obj1.dictLookup("Matrix", &obj2)->isArray() &&
491
0
      obj2.arrayGetLength() == 9) {
492
0
    for (i = 0; i < 9; ++i) {
493
0
      obj2.arrayGet(i, &obj3);
494
0
      cs->mat[i] = obj3.getNum();
495
0
      obj3.free();
496
0
    }
497
0
  }
498
0
  obj2.free();
499
0
  obj1.free();
500
0
  return cs;
501
0
}
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
0
         GfxRenderingIntent ri) {
513
0
  rgb->r = clip01(color->c[0]);
514
0
  rgb->g = clip01(color->c[1]);
515
0
  rgb->b = clip01(color->c[2]);
516
0
}
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
0
void GfxCalRGBColorSpace::getDefaultColor(GfxColor *color) {
541
0
  color->c[0] = 0;
542
0
  color->c[1] = 0;
543
0
  color->c[2] = 0;
544
0
}
545
546
//------------------------------------------------------------------------
547
// GfxDeviceCMYKColorSpace
548
//------------------------------------------------------------------------
549
550
0
GfxDeviceCMYKColorSpace::GfxDeviceCMYKColorSpace() {
551
0
}
552
553
GfxDeviceCMYKColorSpace::~GfxDeviceCMYKColorSpace() {
554
}
555
556
0
GfxColorSpace *GfxDeviceCMYKColorSpace::copy() {
557
0
  GfxDeviceCMYKColorSpace *cs;
558
559
0
  cs = new GfxDeviceCMYKColorSpace();
560
0
  return cs;
561
0
}
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
0
             GfxRenderingIntent ri) {
574
0
  double c, m, y, k, c1, m1, y1, k1, r, g, b, x;
575
576
0
  c = colToDbl(color->c[0]);
577
0
  m = colToDbl(color->c[1]);
578
0
  y = colToDbl(color->c[2]);
579
0
  k = colToDbl(color->c[3]);
580
0
  c1 = 1 - c;
581
0
  m1 = 1 - m;
582
0
  y1 = 1 - y;
583
0
  k1 = 1 - k;
584
  // this is a matrix multiplication, unrolled for performance
585
  //                        C M Y K
586
0
  x = c1 * m1 * y1 * k1; // 0 0 0 0
587
0
  r = g = b = x;
588
0
  x = c1 * m1 * y1 * k;  // 0 0 0 1
589
0
  r += 0.1373 * x;
590
0
  g += 0.1216 * x;
591
0
  b += 0.1255 * x;
592
0
  x = c1 * m1 * y  * k1; // 0 0 1 0
593
0
  r += x;
594
0
  g += 0.9490 * x;
595
0
  x = c1 * m1 * y  * k;  // 0 0 1 1
596
0
  r += 0.1098 * x;
597
0
  g += 0.1020 * x;
598
0
  x = c1 * m  * y1 * k1; // 0 1 0 0
599
0
  r += 0.9255 * x;
600
0
  b += 0.5490 * x;
601
0
  x = c1 * m  * y1 * k;  // 0 1 0 1
602
0
  r += 0.1412 * x;
603
0
  x = c1 * m  * y  * k1; // 0 1 1 0
604
0
  r += 0.9294 * x;
605
0
  g += 0.1098 * x;
606
0
  b += 0.1412 * x;
607
0
  x = c1 * m  * y  * k;  // 0 1 1 1
608
0
  r += 0.1333 * x;
609
0
  x = c  * m1 * y1 * k1; // 1 0 0 0
610
0
  g += 0.6784 * x;
611
0
  b += 0.9373 * x;
612
0
  x = c  * m1 * y1 * k;  // 1 0 0 1
613
0
  g += 0.0588 * x;
614
0
  b += 0.1412 * x;
615
0
  x = c  * m1 * y  * k1; // 1 0 1 0
616
0
  g += 0.6510 * x;
617
0
  b += 0.3137 * x;
618
0
  x = c  * m1 * y  * k;  // 1 0 1 1
619
0
  g += 0.0745 * x;
620
0
  x = c  * m  * y1 * k1; // 1 1 0 0
621
0
  r += 0.1804 * x;
622
0
  g += 0.1922 * x;
623
0
  b += 0.5725 * x;
624
0
  x = c  * m  * y1 * k;  // 1 1 0 1
625
0
  b += 0.0078 * x;
626
0
  x = c  * m  * y  * k1; // 1 1 1 0
627
0
  r += 0.2118 * x;
628
0
  g += 0.2119 * x;
629
0
  b += 0.2235 * x;
630
0
  rgb->r = clip01(dblToCol(r));
631
0
  rgb->g = clip01(dblToCol(g));
632
0
  rgb->b = clip01(dblToCol(b));
633
0
}
634
635
void GfxDeviceCMYKColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk,
636
0
              GfxRenderingIntent ri) {
637
0
  cmyk->c = clip01(color->c[0]);
638
0
  cmyk->m = clip01(color->c[1]);
639
0
  cmyk->y = clip01(color->c[2]);
640
0
  cmyk->k = clip01(color->c[3]);
641
0
}
642
643
644
645
0
void GfxDeviceCMYKColorSpace::getDefaultColor(GfxColor *color) {
646
0
  color->c[0] = 0;
647
0
  color->c[1] = 0;
648
0
  color->c[2] = 0;
649
0
  color->c[3] = gfxColorComp1;
650
0
}
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
0
GfxLabColorSpace::GfxLabColorSpace() {
666
0
  whiteX = whiteY = whiteZ = 1;
667
0
  blackX = blackY = blackZ = 0;
668
0
  aMin = bMin = -100;
669
0
  aMax = bMax = 100;
670
0
}
671
672
GfxLabColorSpace::~GfxLabColorSpace() {
673
}
674
675
0
GfxColorSpace *GfxLabColorSpace::copy() {
676
0
  GfxLabColorSpace *cs;
677
678
0
  cs = new GfxLabColorSpace();
679
0
  cs->whiteX = whiteX;
680
0
  cs->whiteY = whiteY;
681
0
  cs->whiteZ = whiteZ;
682
0
  cs->blackX = blackX;
683
0
  cs->blackY = blackY;
684
0
  cs->blackZ = blackZ;
685
0
  cs->aMin = aMin;
686
0
  cs->aMax = aMax;
687
0
  cs->bMin = bMin;
688
0
  cs->bMax = bMax;
689
0
  cs->kr = kr;
690
0
  cs->kg = kg;
691
0
  cs->kb = kb;
692
0
  return cs;
693
0
}
694
695
0
GfxColorSpace *GfxLabColorSpace::parse(Array *arr, int recursion) {
696
0
  GfxLabColorSpace *cs;
697
0
  Object obj1, obj2, obj3;
698
699
0
  if (arr->getLength() < 2) {
700
0
    error(errSyntaxError, -1, "Bad Lab color space");
701
0
    return NULL;
702
0
  }
703
0
  arr->get(1, &obj1);
704
0
  if (!obj1.isDict()) {
705
0
    error(errSyntaxError, -1, "Bad Lab color space");
706
0
    obj1.free();
707
0
    return NULL;
708
0
  }
709
0
  cs = new GfxLabColorSpace();
710
0
  if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
711
0
      obj2.arrayGetLength() == 3) {
712
0
    obj2.arrayGet(0, &obj3);
713
0
    cs->whiteX = obj3.getNum();
714
0
    obj3.free();
715
0
    obj2.arrayGet(1, &obj3);
716
0
    cs->whiteY = obj3.getNum();
717
0
    obj3.free();
718
0
    obj2.arrayGet(2, &obj3);
719
0
    cs->whiteZ = obj3.getNum();
720
0
    obj3.free();
721
0
  }
722
0
  obj2.free();
723
0
  if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
724
0
      obj2.arrayGetLength() == 3) {
725
0
    obj2.arrayGet(0, &obj3);
726
0
    cs->blackX = obj3.getNum();
727
0
    obj3.free();
728
0
    obj2.arrayGet(1, &obj3);
729
0
    cs->blackY = obj3.getNum();
730
0
    obj3.free();
731
0
    obj2.arrayGet(2, &obj3);
732
0
    cs->blackZ = obj3.getNum();
733
0
    obj3.free();
734
0
  }
735
0
  obj2.free();
736
0
  if (obj1.dictLookup("Range", &obj2)->isArray() &&
737
0
      obj2.arrayGetLength() == 4) {
738
0
    obj2.arrayGet(0, &obj3);
739
0
    cs->aMin = obj3.getNum();
740
0
    obj3.free();
741
0
    obj2.arrayGet(1, &obj3);
742
0
    cs->aMax = obj3.getNum();
743
0
    obj3.free();
744
0
    obj2.arrayGet(2, &obj3);
745
0
    cs->bMin = obj3.getNum();
746
0
    obj3.free();
747
0
    obj2.arrayGet(3, &obj3);
748
0
    cs->bMax = obj3.getNum();
749
0
    obj3.free();
750
0
  }
751
0
  obj2.free();
752
0
  obj1.free();
753
754
0
  cs->kr = 1 / (xyzrgb[0][0] * cs->whiteX +
755
0
    xyzrgb[0][1] * cs->whiteY +
756
0
    xyzrgb[0][2] * cs->whiteZ);
757
0
  cs->kg = 1 / (xyzrgb[1][0] * cs->whiteX +
758
0
    xyzrgb[1][1] * cs->whiteY +
759
0
    xyzrgb[1][2] * cs->whiteZ);
760
0
  cs->kb = 1 / (xyzrgb[2][0] * cs->whiteX +
761
0
    xyzrgb[2][1] * cs->whiteY +
762
0
    xyzrgb[2][2] * cs->whiteZ);
763
764
0
  return cs;
765
0
}
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
0
            GfxRenderingIntent ri) {
780
0
  double X, Y, Z;
781
0
  double t1, t2;
782
0
  double r, g, b;
783
784
785
  // convert L*a*b* to CIE 1931 XYZ color space
786
0
  t1 = (colToDbl(color->c[0]) + 16) / 116;
787
0
  t2 = t1 + colToDbl(color->c[1]) / 500;
788
0
  if (t2 >= (6.0 / 29.0)) {
789
0
    X = t2 * t2 * t2;
790
0
  } else {
791
0
    X = (108.0 / 841.0) * (t2 - (4.0 / 29.0));
792
0
  }
793
0
  X *= whiteX;
794
0
  if (t1 >= (6.0 / 29.0)) {
795
0
    Y = t1 * t1 * t1;
796
0
  } else {
797
0
    Y = (108.0 / 841.0) * (t1 - (4.0 / 29.0));
798
0
  }
799
0
  Y *= whiteY;
800
0
  t2 = t1 - colToDbl(color->c[2]) / 200;
801
0
  if (t2 >= (6.0 / 29.0)) {
802
0
    Z = t2 * t2 * t2;
803
0
  } else {
804
0
    Z = (108.0 / 841.0) * (t2 - (4.0 / 29.0));
805
0
  }
806
0
  Z *= whiteZ;
807
808
  // convert XYZ to RGB, including gamut mapping and gamma correction
809
0
  r = xyzrgb[0][0] * X + xyzrgb[0][1] * Y + xyzrgb[0][2] * Z;
810
0
  g = xyzrgb[1][0] * X + xyzrgb[1][1] * Y + xyzrgb[1][2] * Z;
811
0
  b = xyzrgb[2][0] * X + xyzrgb[2][1] * Y + xyzrgb[2][2] * Z;
812
0
  rgb->r = dblToCol(pow(clip01(r * kr), 0.5));
813
0
  rgb->g = dblToCol(pow(clip01(g * kg), 0.5));
814
0
  rgb->b = dblToCol(pow(clip01(b * kb), 0.5));
815
0
}
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
0
void GfxLabColorSpace::getDefaultColor(GfxColor *color) {
843
0
  color->c[0] = 0;
844
0
  if (aMin > 0) {
845
0
    color->c[1] = dblToCol(aMin);
846
0
  } else if (aMax < 0) {
847
0
    color->c[1] = dblToCol(aMax);
848
0
  } else {
849
0
    color->c[1] = 0;
850
0
  }
851
0
  if (bMin > 0) {
852
0
    color->c[2] = dblToCol(bMin);
853
0
  } else if (bMax < 0) {
854
0
    color->c[2] = dblToCol(bMax);
855
0
  } else {
856
0
    color->c[2] = 0;
857
0
  }
858
0
}
859
860
void GfxLabColorSpace::getDefaultRanges(double *decodeLow, double *decodeRange,
861
0
          int maxImgPixel) {
862
0
  decodeLow[0] = 0;
863
0
  decodeRange[0] = 100;
864
0
  decodeLow[1] = aMin;
865
0
  decodeRange[1] = aMax - aMin;
866
0
  decodeLow[2] = bMin;
867
0
  decodeRange[2] = bMax - bMin;
868
0
}
869
870
//------------------------------------------------------------------------
871
// GfxICCBasedColorSpace
872
//------------------------------------------------------------------------
873
874
GfxICCBasedColorSpace::GfxICCBasedColorSpace(int nCompsA, GfxColorSpace *altA,
875
0
               Ref *iccProfileStreamA) {
876
0
  nComps = nCompsA;
877
0
  alt = altA;
878
0
  iccProfileStream = *iccProfileStreamA;
879
0
  rangeMin[0] = rangeMin[1] = rangeMin[2] = rangeMin[3] = 0;
880
0
  rangeMax[0] = rangeMax[1] = rangeMax[2] = rangeMax[3] = 1;
881
0
}
882
883
0
GfxICCBasedColorSpace::~GfxICCBasedColorSpace() {
884
0
  delete alt;
885
0
}
886
887
0
GfxColorSpace *GfxICCBasedColorSpace::copy() {
888
0
  GfxICCBasedColorSpace *cs;
889
0
  int i;
890
891
0
  cs = new GfxICCBasedColorSpace(nComps, alt->copy(), &iccProfileStream);
892
0
  for (i = 0; i < 4; ++i) {
893
0
    cs->rangeMin[i] = rangeMin[i];
894
0
    cs->rangeMax[i] = rangeMax[i];
895
0
  }
896
0
  return cs;
897
0
}
898
899
GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr,
900
0
              int recursion) {
901
0
  GfxICCBasedColorSpace *cs;
902
0
  Ref iccProfileStreamA;
903
0
  int nCompsA;
904
0
  GfxColorSpace *altA;
905
0
  Dict *dict;
906
0
  Object obj1, obj2, obj3;
907
0
  int i;
908
909
0
  if (arr->getLength() < 2) {
910
0
    error(errSyntaxError, -1, "Bad ICCBased color space");
911
0
    return NULL;
912
0
  }
913
0
  arr->getNF(1, &obj1);
914
0
  if (obj1.isRef()) {
915
0
    iccProfileStreamA = obj1.getRef();
916
0
  } else {
917
0
    iccProfileStreamA.num = 0;
918
0
    iccProfileStreamA.gen = 0;
919
0
  }
920
0
  obj1.free();
921
0
  arr->get(1, &obj1);
922
0
  if (!obj1.isStream()) {
923
0
    error(errSyntaxError, -1, "Bad ICCBased color space (stream)");
924
0
    obj1.free();
925
0
    return NULL;
926
0
  }
927
0
  dict = obj1.streamGetDict();
928
0
  if (!dict->lookup("N", &obj2)->isInt()) {
929
0
    error(errSyntaxError, -1, "Bad ICCBased color space (N)");
930
0
    obj2.free();
931
0
    obj1.free();
932
0
    return NULL;
933
0
  }
934
0
  nCompsA = obj2.getInt();
935
0
  obj2.free();
936
0
  if (!dict->lookup("Alternate", &obj2)->isNull() &&
937
0
      (altA = GfxColorSpace::parse(&obj2,
938
0
           recursion + 1))) {
939
0
    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
0
  } else {
945
0
    switch (nCompsA) {
946
0
    case 1:
947
0
      altA = GfxColorSpace::create(csDeviceGray);
948
0
      break;
949
0
    case 3:
950
0
      altA = GfxColorSpace::create(csDeviceRGB);
951
0
      break;
952
0
    case 4:
953
0
      altA = GfxColorSpace::create(csDeviceCMYK);
954
0
      break;
955
0
    default:
956
0
      error(errSyntaxError, -1, "Bad ICCBased color space - invalid N");
957
0
      obj2.free();
958
0
      obj1.free();
959
0
      return NULL;
960
0
    }
961
0
  }
962
0
  obj2.free();
963
0
  cs = new GfxICCBasedColorSpace(nCompsA, altA, &iccProfileStreamA);
964
0
  if (dict->lookup("Range", &obj2)->isArray() &&
965
0
      obj2.arrayGetLength() == 2 * nCompsA) {
966
0
    for (i = 0; i < nCompsA; ++i) {
967
0
      obj2.arrayGet(2*i, &obj3);
968
0
      cs->rangeMin[i] = obj3.getNum();
969
0
      obj3.free();
970
0
      obj2.arrayGet(2*i+1, &obj3);
971
0
      cs->rangeMax[i] = obj3.getNum();
972
0
      obj3.free();
973
0
    }
974
0
  }
975
0
  obj2.free();
976
0
  obj1.free();
977
0
  return cs;
978
0
}
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
0
           GfxRenderingIntent ri) {
988
0
  alt->getRGB(color, rgb, ri);
989
0
}
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
0
void GfxICCBasedColorSpace::getDefaultColor(GfxColor *color) {
999
0
  int i;
1000
1001
0
  for (i = 0; i < nComps; ++i) {
1002
0
    if (rangeMin[i] > 0) {
1003
0
      color->c[i] = dblToCol(rangeMin[i]);
1004
0
    } else if (rangeMax[i] < 0) {
1005
0
      color->c[i] = dblToCol(rangeMax[i]);
1006
0
    } else {
1007
0
      color->c[i] = 0;
1008
0
    }
1009
0
  }
1010
0
}
1011
1012
void GfxICCBasedColorSpace::getDefaultRanges(double *decodeLow,
1013
               double *decodeRange,
1014
0
               int maxImgPixel) {
1015
0
  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
0
}
1028
1029
1030
//------------------------------------------------------------------------
1031
// GfxIndexedColorSpace
1032
//------------------------------------------------------------------------
1033
1034
GfxIndexedColorSpace::GfxIndexedColorSpace(GfxColorSpace *baseA,
1035
0
             int indexHighA) {
1036
0
  base = baseA;
1037
0
  indexHigh = indexHighA;
1038
0
  lookup = (Guchar *)gmallocn((indexHigh + 1) * base->getNComps(),
1039
0
            sizeof(Guchar));
1040
0
  overprintMask = base->getOverprintMask();
1041
0
}
1042
1043
0
GfxIndexedColorSpace::~GfxIndexedColorSpace() {
1044
0
  delete base;
1045
0
  gfree(lookup);
1046
0
}
1047
1048
0
GfxColorSpace *GfxIndexedColorSpace::copy() {
1049
0
  GfxIndexedColorSpace *cs;
1050
1051
0
  cs = new GfxIndexedColorSpace(base->copy(), indexHigh);
1052
0
  memcpy(cs->lookup, lookup,
1053
0
   (indexHigh + 1) * base->getNComps() * sizeof(Guchar));
1054
0
  return cs;
1055
0
}
1056
1057
GfxColorSpace *GfxIndexedColorSpace::parse(Array *arr,
1058
0
             int recursion) {
1059
0
  GfxIndexedColorSpace *cs;
1060
0
  GfxColorSpace *baseA;
1061
0
  int indexHighA;
1062
0
  Object obj1;
1063
0
  int x;
1064
0
  char *s;
1065
0
  int n, i, j;
1066
1067
0
  if (arr->getLength() != 4) {
1068
0
    error(errSyntaxError, -1, "Bad Indexed color space");
1069
0
    goto err1;
1070
0
  }
1071
0
  arr->get(1, &obj1);
1072
0
  if (!(baseA = GfxColorSpace::parse(&obj1,
1073
0
             recursion + 1))) {
1074
0
    error(errSyntaxError, -1, "Bad Indexed color space (base color space)");
1075
0
    goto err2;
1076
0
  }
1077
0
  obj1.free();
1078
0
  if (!arr->get(2, &obj1)->isInt()) {
1079
0
    error(errSyntaxError, -1, "Bad Indexed color space (hival)");
1080
0
    delete baseA;
1081
0
    goto err2;
1082
0
  }
1083
0
  indexHighA = obj1.getInt();
1084
0
  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
0
    error(errSyntaxError, -1,
1090
0
    "Bad Indexed color space (invalid indexHigh value)");
1091
0
    delete baseA;
1092
0
    goto err2;
1093
0
  }
1094
0
  obj1.free();
1095
0
  cs = new GfxIndexedColorSpace(baseA, indexHighA);
1096
0
  arr->get(3, &obj1);
1097
0
  n = baseA->getNComps();
1098
0
  if (obj1.isStream()) {
1099
0
    obj1.streamReset();
1100
0
    for (i = 0; i <= indexHighA; ++i) {
1101
0
      for (j = 0; j < n; ++j) {
1102
0
  if ((x = obj1.streamGetChar()) == EOF) {
1103
0
    error(errSyntaxError, -1,
1104
0
    "Bad Indexed color space (lookup table stream too short)");
1105
0
    cs->indexHigh = indexHighA = i - 1;
1106
0
    if (cs->indexHigh < 0) {
1107
0
      goto err3;
1108
0
    }
1109
0
  }
1110
0
  cs->lookup[i*n + j] = (Guchar)x;
1111
0
      }
1112
0
    }
1113
0
    obj1.streamClose();
1114
0
  } else if (obj1.isString()) {
1115
0
    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
0
    s = obj1.getString()->getCString();
1124
0
    for (i = 0; i <= indexHighA; ++i) {
1125
0
      for (j = 0; j < n; ++j) {
1126
0
  cs->lookup[i*n + j] = (Guchar)*s++;
1127
0
      }
1128
0
    }
1129
0
  } else {
1130
0
    error(errSyntaxError, -1, "Bad Indexed color space (lookup table)");
1131
0
    goto err3;
1132
0
  }
1133
0
  obj1.free();
1134
0
  return cs;
1135
1136
0
 err3:
1137
0
  delete cs;
1138
0
 err2:
1139
0
  obj1.free();
1140
0
 err1:
1141
0
  return NULL;
1142
0
}
1143
1144
1145
GfxColor *GfxIndexedColorSpace::mapColorToBase(GfxColor *color,
1146
0
                 GfxColor *baseColor) {
1147
0
  Guchar *p;
1148
0
  double low[gfxColorMaxComps], range[gfxColorMaxComps];
1149
0
  int n, i, k;
1150
1151
0
  n = base->getNComps();
1152
0
  base->getDefaultRanges(low, range, indexHigh);
1153
0
  k = (int)(colToDbl(color->c[0]) + 0.5);
1154
0
  if (k < 0) {
1155
0
    k = 0;
1156
0
  } else if (k > indexHigh) {
1157
0
    k = indexHigh;
1158
0
  }
1159
0
  p = &lookup[k * n];
1160
0
  for (i = 0; i < n; ++i) {
1161
0
    baseColor->c[i] = dblToCol(low[i] + (p[i] / 255.0) * range[i]);
1162
0
  }
1163
0
  return baseColor;
1164
0
}
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
0
          GfxRenderingIntent ri) {
1175
0
  GfxColor color2;
1176
1177
0
  base->getRGB(mapColorToBase(color, &color2), rgb, ri);
1178
0
}
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
0
void GfxIndexedColorSpace::getDefaultColor(GfxColor *color) {
1190
0
  color->c[0] = 0;
1191
0
}
1192
1193
void GfxIndexedColorSpace::getDefaultRanges(double *decodeLow,
1194
              double *decodeRange,
1195
0
              int maxImgPixel) {
1196
0
  decodeLow[0] = 0;
1197
0
  decodeRange[0] = maxImgPixel;
1198
0
}
1199
1200
//------------------------------------------------------------------------
1201
// GfxSeparationColorSpace
1202
//------------------------------------------------------------------------
1203
1204
GfxSeparationColorSpace::GfxSeparationColorSpace(GString *nameA,
1205
             GfxColorSpace *altA,
1206
0
             Function *funcA) {
1207
0
  name = nameA;
1208
0
  alt = altA;
1209
0
  func = funcA;
1210
0
  nonMarking = !name->cmp("None");
1211
0
  if (!name->cmp("Cyan")) {
1212
0
    overprintMask = 0x01;
1213
0
  } else if (!name->cmp("Magenta")) {
1214
0
    overprintMask = 0x02;
1215
0
  } else if (!name->cmp("Yellow")) {
1216
0
    overprintMask = 0x04;
1217
0
  } else if (!name->cmp("Black")) {
1218
0
    overprintMask = 0x08;
1219
0
  }
1220
0
}
1221
1222
GfxSeparationColorSpace::GfxSeparationColorSpace(GString *nameA,
1223
             GfxColorSpace *altA,
1224
             Function *funcA,
1225
             GBool nonMarkingA,
1226
0
             Guint overprintMaskA) {
1227
0
  name = nameA;
1228
0
  alt = altA;
1229
0
  func = funcA;
1230
0
  nonMarking = nonMarkingA;
1231
0
  overprintMask = overprintMaskA;
1232
0
}
1233
1234
0
GfxSeparationColorSpace::~GfxSeparationColorSpace() {
1235
0
  delete name;
1236
0
  delete alt;
1237
0
  delete func;
1238
0
}
1239
1240
0
GfxColorSpace *GfxSeparationColorSpace::copy() {
1241
0
  GfxSeparationColorSpace *cs;
1242
1243
0
  cs = new GfxSeparationColorSpace(name->copy(), alt->copy(), func->copy(),
1244
0
           nonMarking, overprintMask);
1245
0
  return cs;
1246
0
}
1247
1248
GfxColorSpace *GfxSeparationColorSpace::parse(Array *arr,
1249
0
                int recursion) {
1250
0
  GfxSeparationColorSpace *cs;
1251
0
  GString *nameA;
1252
0
  GfxColorSpace *altA;
1253
0
  Function *funcA;
1254
0
  Object obj1, obj2;
1255
1256
0
  if (arr->getLength() != 4) {
1257
0
    error(errSyntaxError, -1, "Bad Separation color space");
1258
0
    goto err1;
1259
0
  }
1260
0
  if (!arr->get(1, &obj1)->isName()) {
1261
0
    error(errSyntaxError, -1, "Bad Separation color space (name)");
1262
0
    goto err2;
1263
0
  }
1264
0
  nameA = new GString(obj1.getName());
1265
0
  obj1.free();
1266
0
  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
0
  if (obj1.isStream() &&
1270
0
      !obj1.streamGetDict()->lookup("Alternate", &obj2)->isNull()) {
1271
0
    obj1.free();
1272
0
    obj1 = obj2;
1273
0
  }
1274
0
  if (!(altA = GfxColorSpace::parse(&obj1,
1275
0
            recursion + 1))) {
1276
0
    error(errSyntaxError, -1,
1277
0
    "Bad Separation color space (alternate color space)");
1278
0
    goto err3;
1279
0
  }
1280
0
  obj1.free();
1281
0
  arr->get(3, &obj1);
1282
0
  if (!(funcA = Function::parse(&obj1, 1, altA->getNComps()))) {
1283
0
    goto err4;
1284
0
  }
1285
0
  obj1.free();
1286
0
  cs = new GfxSeparationColorSpace(nameA, altA, funcA);
1287
0
  return cs;
1288
1289
0
 err4:
1290
0
  delete altA;
1291
0
 err3:
1292
0
  delete nameA;
1293
0
 err2:
1294
0
  obj1.free();
1295
0
 err1:
1296
0
  return NULL;
1297
0
}
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
0
             GfxRenderingIntent ri) {
1317
0
  double x;
1318
0
  double c[gfxColorMaxComps];
1319
0
  GfxColor color2;
1320
0
  int i;
1321
1322
0
  x = colToDbl(color->c[0]);
1323
0
  func->transform(&x, c);
1324
0
  for (i = 0; i < alt->getNComps(); ++i) {
1325
0
    color2.c[i] = dblToCol(c[i]);
1326
0
  }
1327
0
  alt->getRGB(&color2, rgb, ri);
1328
0
}
1329
1330
void GfxSeparationColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk,
1331
0
              GfxRenderingIntent ri) {
1332
0
  double x;
1333
0
  double c[gfxColorMaxComps];
1334
0
  GfxColor color2;
1335
0
  int i;
1336
1337
0
  x = colToDbl(color->c[0]);
1338
0
  func->transform(&x, c);
1339
0
  for (i = 0; i < alt->getNComps(); ++i) {
1340
0
    color2.c[i] = dblToCol(c[i]);
1341
0
  }
1342
0
  alt->getCMYK(&color2, cmyk, ri);
1343
0
}
1344
1345
1346
1347
0
void GfxSeparationColorSpace::getDefaultColor(GfxColor *color) {
1348
0
  color->c[0] = gfxColorComp1;
1349
0
}
1350
1351
//------------------------------------------------------------------------
1352
// GfxDeviceNColorSpace
1353
//------------------------------------------------------------------------
1354
1355
GfxDeviceNColorSpace::GfxDeviceNColorSpace(int nCompsA,
1356
             GString **namesA,
1357
             GfxColorSpace *altA,
1358
             Function *funcA,
1359
0
             Object *attrsA) {
1360
0
  int i;
1361
1362
0
  nComps = nCompsA;
1363
0
  alt = altA;
1364
0
  func = funcA;
1365
0
  attrsA->copy(&attrs);
1366
0
  nonMarking = gTrue;
1367
0
  overprintMask = 0;
1368
0
  for (i = 0; i < nComps; ++i) {
1369
0
    names[i] = namesA[i];
1370
0
    if (names[i]->cmp("None")) {
1371
0
      nonMarking = gFalse;
1372
0
    }
1373
0
    if (!names[i]->cmp("Cyan")) {
1374
0
      overprintMask |= 0x01;
1375
0
    } else if (!names[i]->cmp("Magenta")) {
1376
0
      overprintMask |= 0x02;
1377
0
    } else if (!names[i]->cmp("Yellow")) {
1378
0
      overprintMask |= 0x04;
1379
0
    } else if (!names[i]->cmp("Black")) {
1380
0
      overprintMask |= 0x08;
1381
0
    } else {
1382
0
      overprintMask = 0x0f;
1383
0
    }
1384
0
  }
1385
0
}
1386
1387
GfxDeviceNColorSpace::GfxDeviceNColorSpace(int nCompsA,
1388
             GString **namesA,
1389
             GfxColorSpace *altA,
1390
             Function *funcA,
1391
             Object *attrsA,
1392
             GBool nonMarkingA,
1393
0
             Guint overprintMaskA) {
1394
0
  int i;
1395
1396
0
  nComps = nCompsA;
1397
0
  alt = altA;
1398
0
  func = funcA;
1399
0
  attrsA->copy(&attrs);
1400
0
  nonMarking = nonMarkingA;
1401
0
  overprintMask = overprintMaskA;
1402
0
  for (i = 0; i < nComps; ++i) {
1403
0
    names[i] = namesA[i]->copy();
1404
0
  }
1405
0
}
1406
1407
0
GfxDeviceNColorSpace::~GfxDeviceNColorSpace() {
1408
0
  int i;
1409
1410
0
  for (i = 0; i < nComps; ++i) {
1411
0
    delete names[i];
1412
0
  }
1413
0
  delete alt;
1414
0
  delete func;
1415
0
  attrs.free();
1416
0
}
1417
1418
0
GfxColorSpace *GfxDeviceNColorSpace::copy() {
1419
0
  GfxDeviceNColorSpace *cs;
1420
1421
0
  cs = new GfxDeviceNColorSpace(nComps, names, alt->copy(), func->copy(),
1422
0
        &attrs, nonMarking, overprintMask);
1423
0
  return cs;
1424
0
}
1425
1426
GfxColorSpace *GfxDeviceNColorSpace::parse(Array *arr,
1427
0
             int recursion) {
1428
0
  GfxDeviceNColorSpace *cs;
1429
0
  int nCompsA;
1430
0
  GString *namesA[gfxColorMaxComps];
1431
0
  GfxColorSpace *altA;
1432
0
  Function *funcA;
1433
0
  Object attrsA, obj1, obj2;
1434
0
  int i;
1435
1436
0
  if (arr->getLength() != 4 && arr->getLength() != 5) {
1437
0
    error(errSyntaxError, -1, "Bad DeviceN color space");
1438
0
    goto err1;
1439
0
  }
1440
0
  if (!arr->get(1, &obj1)->isArray()) {
1441
0
    error(errSyntaxError, -1, "Bad DeviceN color space (names)");
1442
0
    goto err2;
1443
0
  }
1444
0
  nCompsA = obj1.arrayGetLength();
1445
0
  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
0
  for (i = 0; i < nCompsA; ++i) {
1452
0
    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
0
    namesA[i] = new GString(obj2.getName());
1458
0
    obj2.free();
1459
0
  }
1460
0
  obj1.free();
1461
0
  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
0
  if (obj1.isStream() &&
1465
0
      !obj1.streamGetDict()->lookup("Alternate", &obj2)->isNull()) {
1466
0
    obj1.free();
1467
0
    obj1 = obj2;
1468
0
  }
1469
0
  if (!(altA = GfxColorSpace::parse(&obj1,
1470
0
            recursion + 1))) {
1471
0
    error(errSyntaxError, -1,
1472
0
    "Bad DeviceN color space (alternate color space)");
1473
0
    goto err3;
1474
0
  }
1475
0
  obj1.free();
1476
0
  arr->get(3, &obj1);
1477
0
  if (!(funcA = Function::parse(&obj1, nCompsA, altA->getNComps()))) {
1478
0
    goto err4;
1479
0
  }
1480
0
  obj1.free();
1481
0
  if (arr->getLength() == 5) {
1482
0
    arr->get(4, &attrsA);
1483
0
  } else {
1484
0
    attrsA.initNull();
1485
0
  }
1486
0
  cs = new GfxDeviceNColorSpace(nCompsA, namesA, altA, funcA, &attrsA);
1487
0
  attrsA.free();
1488
0
  return cs;
1489
1490
0
 err4:
1491
0
  delete altA;
1492
0
 err3:
1493
0
  for (i = 0; i < nCompsA; ++i) {
1494
0
    delete namesA[i];
1495
0
  }
1496
0
 err2:
1497
0
  obj1.free();
1498
0
 err1:
1499
0
  return NULL;
1500
0
}
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
0
          GfxRenderingIntent ri) {
1521
0
  double x[gfxColorMaxComps], c[gfxColorMaxComps];
1522
0
  GfxColor color2;
1523
0
  int i;
1524
1525
0
  for (i = 0; i < nComps; ++i) {
1526
0
    x[i] = colToDbl(color->c[i]);
1527
0
  }
1528
0
  func->transform(x, c);
1529
0
  for (i = 0; i < alt->getNComps(); ++i) {
1530
0
    color2.c[i] = dblToCol(c[i]);
1531
0
  }
1532
0
  alt->getRGB(&color2, rgb, ri);
1533
0
}
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
0
void GfxDeviceNColorSpace::getDefaultColor(GfxColor *color) {
1554
0
  int i;
1555
1556
0
  for (i = 0; i < nComps; ++i) {
1557
0
    color->c[i] = gfxColorComp1;
1558
0
  }
1559
0
}
1560
1561
//------------------------------------------------------------------------
1562
// GfxPatternColorSpace
1563
//------------------------------------------------------------------------
1564
1565
0
GfxPatternColorSpace::GfxPatternColorSpace(GfxColorSpace *underA) {
1566
0
  under = underA;
1567
0
}
1568
1569
0
GfxPatternColorSpace::~GfxPatternColorSpace() {
1570
0
  if (under) {
1571
0
    delete under;
1572
0
  }
1573
0
}
1574
1575
0
GfxColorSpace *GfxPatternColorSpace::copy() {
1576
0
  GfxPatternColorSpace *cs;
1577
1578
0
  cs = new GfxPatternColorSpace(under ? under->copy() :
1579
0
                (GfxColorSpace *)NULL);
1580
0
  return cs;
1581
0
}
1582
1583
GfxColorSpace *GfxPatternColorSpace::parse(Array *arr,
1584
0
             int recursion) {
1585
0
  GfxPatternColorSpace *cs;
1586
0
  GfxColorSpace *underA;
1587
0
  Object obj1;
1588
1589
0
  if (arr->getLength() != 1 && arr->getLength() != 2) {
1590
0
    error(errSyntaxError, -1, "Bad Pattern color space");
1591
0
    return NULL;
1592
0
  }
1593
0
  underA = NULL;
1594
0
  if (arr->getLength() == 2) {
1595
0
    arr->get(1, &obj1);
1596
0
    if (!(underA = GfxColorSpace::parse(&obj1,
1597
0
          recursion + 1))) {
1598
0
      error(errSyntaxError, -1,
1599
0
      "Bad Pattern color space (underlying color space)");
1600
0
      obj1.free();
1601
0
      return NULL;
1602
0
    }
1603
0
    obj1.free();
1604
0
  }
1605
0
  cs = new GfxPatternColorSpace(underA);
1606
0
  return cs;
1607
0
}
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
0
          GfxRenderingIntent ri) {
1617
0
  rgb->r = rgb->g = rgb->b = 0;
1618
0
}
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
0
void GfxPatternColorSpace::getDefaultColor(GfxColor *color) {
1629
  // not used
1630
0
}
1631
1632
//------------------------------------------------------------------------
1633
// Pattern
1634
//------------------------------------------------------------------------
1635
1636
0
GfxPattern::GfxPattern(int typeA) {
1637
0
  type = typeA;
1638
0
}
1639
1640
0
GfxPattern::~GfxPattern() {
1641
0
}
1642
1643
GfxPattern *GfxPattern::parse(Object *objRef, Object *obj
1644
0
            ) {
1645
0
  GfxPattern *pattern;
1646
0
  Object typeObj;
1647
1648
0
  if (obj->isDict()) {
1649
0
    obj->dictLookup("PatternType", &typeObj);
1650
0
  } else if (obj->isStream()) {
1651
0
    obj->streamGetDict()->lookup("PatternType", &typeObj);
1652
0
  } else {
1653
0
    return NULL;
1654
0
  }
1655
0
  pattern = NULL;
1656
0
  if (typeObj.isInt() && typeObj.getInt() == 1) {
1657
0
    pattern = GfxTilingPattern::parse(objRef, obj);
1658
0
  } else if (typeObj.isInt() && typeObj.getInt() == 2) {
1659
0
    pattern = GfxShadingPattern::parse(obj
1660
0
               );
1661
0
  }
1662
0
  typeObj.free();
1663
0
  return pattern;
1664
0
}
1665
1666
//------------------------------------------------------------------------
1667
// GfxTilingPattern
1668
//------------------------------------------------------------------------
1669
1670
0
GfxTilingPattern *GfxTilingPattern::parse(Object *patObjRef, Object *patObj) {
1671
0
  GfxTilingPattern *pat;
1672
0
  Dict *dict;
1673
0
  int paintTypeA, tilingTypeA;
1674
0
  double bboxA[4], matrixA[6];
1675
0
  double xStepA, yStepA;
1676
0
  Object resDictA;
1677
0
  Object obj1, obj2;
1678
0
  int i;
1679
1680
0
  if (!patObj->isStream()) {
1681
0
    return NULL;
1682
0
  }
1683
0
  dict = patObj->streamGetDict();
1684
1685
0
  if (dict->lookup("PaintType", &obj1)->isInt()) {
1686
0
    paintTypeA = obj1.getInt();
1687
0
  } else {
1688
0
    paintTypeA = 1;
1689
0
    error(errSyntaxWarning, -1, "Invalid or missing PaintType in pattern");
1690
0
  }
1691
0
  obj1.free();
1692
0
  if (dict->lookup("TilingType", &obj1)->isInt()) {
1693
0
    tilingTypeA = obj1.getInt();
1694
0
  } else {
1695
0
    tilingTypeA = 1;
1696
0
    error(errSyntaxWarning, -1, "Invalid or missing TilingType in pattern");
1697
0
  }
1698
0
  obj1.free();
1699
0
  bboxA[0] = bboxA[1] = 0;
1700
0
  bboxA[2] = bboxA[3] = 1;
1701
0
  if (dict->lookup("BBox", &obj1)->isArray() &&
1702
0
      obj1.arrayGetLength() == 4) {
1703
0
    for (i = 0; i < 4; ++i) {
1704
0
      if (obj1.arrayGet(i, &obj2)->isNum()) {
1705
0
  bboxA[i] = obj2.getNum();
1706
0
      }
1707
0
      obj2.free();
1708
0
    }
1709
0
  } else {
1710
0
    error(errSyntaxError, -1, "Invalid or missing BBox in pattern");
1711
0
  }
1712
0
  obj1.free();
1713
0
  if (dict->lookup("XStep", &obj1)->isNum()) {
1714
0
    xStepA = obj1.getNum();
1715
0
  } else {
1716
0
    xStepA = 1;
1717
0
    error(errSyntaxError, -1, "Invalid or missing XStep in pattern");
1718
0
  }
1719
0
  obj1.free();
1720
0
  if (dict->lookup("YStep", &obj1)->isNum()) {
1721
0
    yStepA = obj1.getNum();
1722
0
  } else {
1723
0
    yStepA = 1;
1724
0
    error(errSyntaxError, -1, "Invalid or missing YStep in pattern");
1725
0
  }
1726
0
  obj1.free();
1727
0
  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
0
  matrixA[0] = 1; matrixA[1] = 0;
1733
0
  matrixA[2] = 0; matrixA[3] = 1;
1734
0
  matrixA[4] = 0; matrixA[5] = 0;
1735
0
  if (dict->lookup("Matrix", &obj1)->isArray() &&
1736
0
      obj1.arrayGetLength() == 6) {
1737
0
    for (i = 0; i < 6; ++i) {
1738
0
      if (obj1.arrayGet(i, &obj2)->isNum()) {
1739
0
  matrixA[i] = obj2.getNum();
1740
0
      }
1741
0
      obj2.free();
1742
0
    }
1743
0
  }
1744
0
  obj1.free();
1745
1746
0
  pat = new GfxTilingPattern(paintTypeA, tilingTypeA, bboxA, xStepA, yStepA,
1747
0
           &resDictA, matrixA, patObjRef);
1748
0
  resDictA.free();
1749
0
  return pat;
1750
0
}
1751
1752
GfxTilingPattern::GfxTilingPattern(int paintTypeA, int tilingTypeA,
1753
           double *bboxA, double xStepA, double yStepA,
1754
           Object *resDictA, double *matrixA,
1755
           Object *contentStreamRefA):
1756
0
  GfxPattern(1)
1757
0
{
1758
0
  int i;
1759
1760
0
  paintType = paintTypeA;
1761
0
  tilingType = tilingTypeA;
1762
0
  for (i = 0; i < 4; ++i) {
1763
0
    bbox[i] = bboxA[i];
1764
0
  }
1765
0
  xStep = xStepA;
1766
0
  yStep = yStepA;
1767
0
  resDictA->copy(&resDict);
1768
0
  for (i = 0; i < 6; ++i) {
1769
0
    matrix[i] = matrixA[i];
1770
0
  }
1771
0
  contentStreamRefA->copy(&contentStreamRef);
1772
0
}
1773
1774
0
GfxTilingPattern::~GfxTilingPattern() {
1775
0
  resDict.free();
1776
0
  contentStreamRef.free();
1777
0
}
1778
1779
0
GfxPattern *GfxTilingPattern::copy() {
1780
0
  return new GfxTilingPattern(paintType, tilingType, bbox, xStep, yStep,
1781
0
            &resDict, matrix, &contentStreamRef);
1782
0
}
1783
1784
0
GBool GfxTilingPattern::usesBlendMode(XRef *xref) {
1785
0
  char *scannedObjs = (char *)gmalloc(xref->getNumObjects());
1786
0
  memset(scannedObjs, 0, xref->getNumObjects());
1787
0
  GBool ret = scanResourcesForBlendMode(&resDict, scannedObjs, xref);
1788
0
  gfree(scannedObjs);
1789
0
  return ret;
1790
0
}
1791
1792
GBool GfxTilingPattern::scanResourcesForBlendMode(Object *resDict2,
1793
              char *scannedObjs,
1794
0
              XRef *xref) {
1795
0
  Object ref1, obj1, obj2;
1796
1797
0
  if (!resDict2->isDict()) {
1798
0
    return gFalse;
1799
0
  }
1800
1801
  //----- ExtGStates
1802
0
  resDict2->dictLookupNF("ExtGState", &ref1);
1803
0
  if (!ref1.isRef() || (ref1.getRefNum() < xref->getNumObjects() &&
1804
0
      !scannedObjs[ref1.getRefNum()])) {
1805
0
    if (ref1.isRef()) {
1806
0
      scannedObjs[ref1.getRefNum()] = 1;
1807
0
      ref1.fetch(xref, &obj1);
1808
0
    } else {
1809
0
      ref1.copy(&obj1);
1810
0
    }
1811
0
    if (obj1.isDict()) {
1812
0
      for (int i = 0; i < obj1.dictGetLength(); ++i) {
1813
0
  if (scanExtGStateForBlendMode(obj1.dictGetValNF(i, &obj2),
1814
0
              scannedObjs, xref)) {
1815
0
    obj2.free();
1816
0
    obj1.free();
1817
0
    ref1.free();
1818
0
    return gTrue;
1819
0
  }
1820
0
  obj2.free();
1821
0
      }
1822
0
    }
1823
0
    obj1.free();
1824
0
  }
1825
0
  ref1.free();
1826
1827
  //----- patterns
1828
0
  resDict2->dictLookupNF("Pattern", &ref1);
1829
0
  if (!ref1.isRef() || (ref1.getRefNum() < xref->getNumObjects() &&
1830
0
      !scannedObjs[ref1.getRefNum()])) {
1831
0
    if (ref1.isRef()) {
1832
0
      scannedObjs[ref1.getRefNum()] = 1;
1833
0
      ref1.fetch(xref, &obj1);
1834
0
    } else {
1835
0
      ref1.copy(&obj1);
1836
0
    }
1837
0
    if (obj1.isDict()) {
1838
0
      for (int i = 0; i < obj1.dictGetLength(); ++i) {
1839
0
  if (scanPatternForBlendMode(obj1.dictGetValNF(i, &obj2),
1840
0
            scannedObjs, xref)) {
1841
0
    obj2.free();
1842
0
    obj1.free();
1843
0
    ref1.free();
1844
0
    return gTrue;
1845
0
  }
1846
0
  obj2.free();
1847
0
      }
1848
0
    }
1849
0
    obj1.free();
1850
0
  }
1851
0
  ref1.free();
1852
1853
  //----- XObjects
1854
0
  resDict2->dictLookupNF("XObject", &ref1);
1855
0
  if (!ref1.isRef() || (ref1.getRefNum() < xref->getNumObjects() &&
1856
0
      !scannedObjs[ref1.getRefNum()])) {
1857
0
    if (ref1.isRef()) {
1858
0
      scannedObjs[ref1.getRefNum()] = 1;
1859
0
      ref1.fetch(xref, &obj1);
1860
0
    } else {
1861
0
      ref1.copy(&obj1);
1862
0
    }
1863
0
    if (obj1.isDict()) {
1864
0
      for (int i = 0; i < obj1.dictGetLength(); ++i) {
1865
0
  if (scanXObjectForBlendMode(obj1.dictGetValNF(i, &obj2),
1866
0
            scannedObjs, xref)) {
1867
0
    obj2.free();
1868
0
    obj1.free();
1869
0
    ref1.free();
1870
0
    return gTrue;
1871
0
  }
1872
0
  obj2.free();
1873
0
      }
1874
0
    }
1875
0
    obj1.free();
1876
0
  }
1877
0
  ref1.free();
1878
1879
0
  return gFalse;
1880
0
}
1881
1882
GBool GfxTilingPattern::scanExtGStateForBlendMode(Object *gsObj,
1883
              char *scannedObjs,
1884
0
              XRef *xref) {
1885
0
  Object gsDict, obj1;
1886
1887
0
  if (gsObj->isRef()) {
1888
0
    if (gsObj->getRefNum() >= xref->getNumObjects() ||
1889
0
  scannedObjs[gsObj->getRefNum()]) {
1890
0
      return gFalse;
1891
0
    }
1892
0
    scannedObjs[gsObj->getRefNum()] = 1;
1893
0
    gsObj->fetch(xref, &gsDict);
1894
0
  } else {
1895
0
    gsObj->copy(&gsDict);
1896
0
  }
1897
0
  if (!gsDict.isDict()) {
1898
0
    gsDict.free();
1899
0
    return gFalse;
1900
0
  }
1901
1902
0
  gsDict.dictLookup("BM", &obj1);
1903
0
  if (obj1.isName() && !obj1.isName("Normal")) {
1904
0
    obj1.free();
1905
0
    gsDict.free();
1906
0
    return gTrue;
1907
0
  }
1908
0
  obj1.free();
1909
1910
0
  if (!gsDict.dictLookupNF("SMask", &obj1)->isNull()) {
1911
0
    if (scanSoftMaskForBlendMode(&obj1, scannedObjs, xref)) {
1912
0
      obj1.free();
1913
0
      gsDict.free();
1914
0
      return gTrue;
1915
0
    }
1916
0
  }
1917
0
  obj1.free();
1918
1919
0
  gsDict.free();
1920
1921
0
  return gFalse;
1922
0
}
1923
1924
GBool GfxTilingPattern::scanSoftMaskForBlendMode(Object *softMaskObj,
1925
             char *scannedObjs,
1926
0
             XRef *xref) {
1927
0
  Object softMaskDict, obj1;
1928
1929
0
  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
0
  } else {
1937
0
    softMaskObj->copy(&softMaskDict);
1938
0
  }
1939
0
  if (!softMaskDict.isDict()) {
1940
0
    softMaskDict.free();
1941
0
    return gFalse;
1942
0
  }
1943
1944
0
  if (!softMaskDict.dictLookupNF("G", &obj1)->isNull()) {
1945
0
    if (scanXObjectForBlendMode(&obj1, scannedObjs, xref)) {
1946
0
      obj1.free();
1947
0
      softMaskDict.free();
1948
0
      return gTrue;
1949
0
    }
1950
0
  }
1951
0
  obj1.free();
1952
1953
0
  softMaskDict.free();
1954
1955
0
  return gFalse;
1956
0
}
1957
1958
GBool GfxTilingPattern::scanPatternForBlendMode(Object *patternObj,
1959
            char *scannedObjs,
1960
0
            XRef *xref) {
1961
0
  Object patternObj2, obj1;
1962
0
  Dict *patternDict;
1963
1964
0
  if (patternObj->isRef()) {
1965
0
    if (patternObj->getRefNum() >= xref->getNumObjects() ||
1966
0
  scannedObjs[patternObj->getRefNum()]) {
1967
0
      return gFalse;
1968
0
    }
1969
0
    scannedObjs[patternObj->getRefNum()] = 1;
1970
0
    patternObj->fetch(xref, &patternObj2);
1971
0
  } else {
1972
0
    patternObj->copy(&patternObj2);
1973
0
  }
1974
0
  if (patternObj2.isDict()) {
1975
0
    patternDict = patternObj2.getDict();
1976
0
  } else if (patternObj2.isStream()) {
1977
0
    patternDict = patternObj2.streamGetDict();
1978
0
  } else {
1979
0
    patternObj2.free();
1980
0
    return gFalse;
1981
0
  }
1982
1983
0
  if (!patternDict->lookupNF("Resources", &obj1)->isNull()) {
1984
0
    if (scanResourcesForBlendMode(&obj1, scannedObjs, xref)) {
1985
0
      obj1.free();
1986
0
      patternObj2.free();
1987
0
      return gTrue;
1988
0
    }
1989
0
  }
1990
0
  obj1.free();
1991
1992
0
  patternObj2.free();
1993
1994
0
  return gFalse;
1995
0
}
1996
1997
GBool GfxTilingPattern::scanXObjectForBlendMode(Object *xObj,
1998
            char *scannedObjs,
1999
0
            XRef *xref) {
2000
0
  Object xObj2, obj1;
2001
0
  Dict *dict;
2002
2003
0
  if (xObj->isRef()) {
2004
0
    if (xObj->getRefNum() >= xref->getNumObjects() ||
2005
0
  scannedObjs[xObj->getRefNum()]) {
2006
0
      return gFalse;
2007
0
    }
2008
0
    scannedObjs[xObj->getRefNum()] = 1;
2009
0
    xObj->fetch(xref, &xObj2);
2010
0
  } else {
2011
0
    xObj->copy(&xObj2);
2012
0
  }
2013
0
  if (xObj2.isDict()) {
2014
0
    dict = xObj2.getDict();
2015
0
  } else if (xObj2.isStream()) {
2016
0
    dict = xObj2.streamGetDict();
2017
0
  } else {
2018
0
    xObj2.free();
2019
0
    return gFalse;
2020
0
  }
2021
2022
0
  if (!dict->lookupNF("Resources", &obj1)->isNull()) {
2023
0
    if (scanResourcesForBlendMode(&obj1, scannedObjs, xref)) {
2024
0
      obj1.free();
2025
0
      xObj2.free();
2026
0
      return gTrue;
2027
0
    }
2028
0
  }
2029
0
  obj1.free();
2030
2031
0
  xObj2.free();
2032
2033
0
  return gFalse;
2034
0
}
2035
2036
//------------------------------------------------------------------------
2037
// GfxShadingPattern
2038
//------------------------------------------------------------------------
2039
2040
GfxShadingPattern *GfxShadingPattern::parse(Object *patObj
2041
0
              ) {
2042
0
  Dict *dict;
2043
0
  GfxShading *shadingA;
2044
0
  double matrixA[6];
2045
0
  Object obj1, obj2;
2046
0
  int i;
2047
2048
0
  if (!patObj->isDict()) {
2049
0
    return NULL;
2050
0
  }
2051
0
  dict = patObj->getDict();
2052
2053
0
  dict->lookup("Shading", &obj1);
2054
0
  shadingA = GfxShading::parse(&obj1
2055
0
             );
2056
0
  obj1.free();
2057
0
  if (!shadingA) {
2058
0
    return NULL;
2059
0
  }
2060
2061
0
  matrixA[0] = 1; matrixA[1] = 0;
2062
0
  matrixA[2] = 0; matrixA[3] = 1;
2063
0
  matrixA[4] = 0; matrixA[5] = 0;
2064
0
  if (dict->lookup("Matrix", &obj1)->isArray() &&
2065
0
      obj1.arrayGetLength() == 6) {
2066
0
    for (i = 0; i < 6; ++i) {
2067
0
      if (obj1.arrayGet(i, &obj2)->isNum()) {
2068
0
  matrixA[i] = obj2.getNum();
2069
0
      }
2070
0
      obj2.free();
2071
0
    }
2072
0
  }
2073
0
  obj1.free();
2074
2075
0
  return new GfxShadingPattern(shadingA, matrixA);
2076
0
}
2077
2078
GfxShadingPattern::GfxShadingPattern(GfxShading *shadingA, double *matrixA):
2079
0
  GfxPattern(2)
2080
0
{
2081
0
  int i;
2082
2083
0
  shading = shadingA;
2084
0
  for (i = 0; i < 6; ++i) {
2085
0
    matrix[i] = matrixA[i];
2086
0
  }
2087
0
}
2088
2089
0
GfxShadingPattern::~GfxShadingPattern() {
2090
0
  delete shading;
2091
0
}
2092
2093
0
GfxPattern *GfxShadingPattern::copy() {
2094
0
  return new GfxShadingPattern(shading->copy(), matrix);
2095
0
}
2096
2097
//------------------------------------------------------------------------
2098
// GfxShading
2099
//------------------------------------------------------------------------
2100
2101
0
GfxShading::GfxShading(int typeA) {
2102
0
  type = typeA;
2103
0
  colorSpace = NULL;
2104
0
}
2105
2106
0
GfxShading::GfxShading(GfxShading *shading) {
2107
0
  int i;
2108
2109
0
  type = shading->type;
2110
0
  colorSpace = shading->colorSpace->copy();
2111
0
  for (i = 0; i < gfxColorMaxComps; ++i) {
2112
0
    background.c[i] = shading->background.c[i];
2113
0
  }
2114
0
  hasBackground = shading->hasBackground;
2115
0
  xMin = shading->xMin;
2116
0
  yMin = shading->yMin;
2117
0
  xMax = shading->xMax;
2118
0
  yMax = shading->yMax;
2119
0
  hasBBox = shading->hasBBox;
2120
0
}
2121
2122
0
GfxShading::~GfxShading() {
2123
0
  if (colorSpace) {
2124
0
    delete colorSpace;
2125
0
  }
2126
0
}
2127
2128
GfxShading *GfxShading::parse(Object *obj
2129
0
            ) {
2130
0
  GfxShading *shading;
2131
0
  Dict *dict;
2132
0
  int typeA;
2133
0
  Object obj1;
2134
2135
0
  if (obj->isDict()) {
2136
0
    dict = obj->getDict();
2137
0
  } else if (obj->isStream()) {
2138
0
    dict = obj->streamGetDict();
2139
0
  } else {
2140
0
    return NULL;
2141
0
  }
2142
2143
0
  if (!dict->lookup("ShadingType", &obj1)->isInt()) {
2144
0
    error(errSyntaxError, -1, "Invalid ShadingType in shading dictionary");
2145
0
    obj1.free();
2146
0
    return NULL;
2147
0
  }
2148
0
  typeA = obj1.getInt();
2149
0
  obj1.free();
2150
2151
0
  switch (typeA) {
2152
0
  case 1:
2153
0
    shading = GfxFunctionShading::parse(dict
2154
0
          );
2155
0
    break;
2156
0
  case 2:
2157
0
    shading = GfxAxialShading::parse(dict
2158
0
             );
2159
0
    break;
2160
0
  case 3:
2161
0
    shading = GfxRadialShading::parse(dict
2162
0
              );
2163
0
    break;
2164
0
  case 4:
2165
0
    if (obj->isStream()) {
2166
0
      shading = GfxGouraudTriangleShading::parse(4, dict, obj->getStream()
2167
0
             );
2168
0
    } else {
2169
0
      error(errSyntaxError, -1, "Invalid Type 4 shading object");
2170
0
      goto err1;
2171
0
    }
2172
0
    break;
2173
0
  case 5:
2174
0
    if (obj->isStream()) {
2175
0
      shading = GfxGouraudTriangleShading::parse(5, dict, obj->getStream()
2176
0
             );
2177
0
    } else {
2178
0
      error(errSyntaxError, -1, "Invalid Type 5 shading object");
2179
0
      goto err1;
2180
0
    }
2181
0
    break;
2182
0
  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
0
  case 7:
2192
0
    if (obj->isStream()) {
2193
0
      shading = GfxPatchMeshShading::parse(7, dict, obj->getStream()
2194
0
             );
2195
0
    } else {
2196
0
      error(errSyntaxError, -1, "Invalid Type 7 shading object");
2197
0
      goto err1;
2198
0
    }
2199
0
    break;
2200
0
  default:
2201
0
    error(errSyntaxError, -1, "Unknown shading type {0:d}", typeA);
2202
0
    goto err1;
2203
0
  }
2204
2205
0
  return shading;
2206
2207
0
 err1:
2208
0
  return NULL;
2209
0
}
2210
2211
GBool GfxShading::init(Dict *dict
2212
0
           ) {
2213
0
  Object obj1, obj2;
2214
0
  int i;
2215
2216
0
  dict->lookup("ColorSpace", &obj1);
2217
0
  if (!(colorSpace = GfxColorSpace::parse(&obj1
2218
0
            ))) {
2219
0
    error(errSyntaxError, -1, "Bad color space in shading dictionary");
2220
0
    obj1.free();
2221
0
    return gFalse;
2222
0
  }
2223
0
  obj1.free();
2224
2225
0
  for (i = 0; i < gfxColorMaxComps; ++i) {
2226
0
    background.c[i] = 0;
2227
0
  }
2228
0
  hasBackground = gFalse;
2229
0
  if (dict->lookup("Background", &obj1)->isArray()) {
2230
0
    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
0
    } else {
2237
0
      error(errSyntaxError, -1, "Bad Background in shading dictionary");
2238
0
    }
2239
0
  }
2240
0
  obj1.free();
2241
2242
0
  xMin = yMin = xMax = yMax = 0;
2243
0
  hasBBox = gFalse;
2244
0
  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
0
  obj1.free();
2260
2261
0
  return gTrue;
2262
0
}
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
0
                ) {
2317
0
  GfxFunctionShading *shading;
2318
0
  double x0A, y0A, x1A, y1A;
2319
0
  double matrixA[6];
2320
0
  Function *funcsA[gfxColorMaxComps];
2321
0
  int nFuncsA;
2322
0
  Object obj1, obj2;
2323
0
  GBool ok;
2324
0
  int i;
2325
2326
0
  x0A = y0A = 0;
2327
0
  x1A = y1A = 1;
2328
0
  if (dict->lookup("Domain", &obj1)->isArray() &&
2329
0
      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
0
  obj1.free();
2340
2341
0
  matrixA[0] = 1; matrixA[1] = 0;
2342
0
  matrixA[2] = 0; matrixA[3] = 1;
2343
0
  matrixA[4] = 0; matrixA[5] = 0;
2344
0
  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
0
  obj1.free();
2360
2361
0
  dict->lookup("Function", &obj1);
2362
0
  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
0
  } else {
2377
0
    nFuncsA = 1;
2378
0
    if (!(funcsA[0] = Function::parse(&obj1, 2, -1))) {
2379
0
      goto err1;
2380
0
    }
2381
0
  }
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
0
 err1:
2413
0
  obj1.free();
2414
0
  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
0
  GfxShading(2)
2450
0
{
2451
0
  int i;
2452
2453
0
  x0 = x0A;
2454
0
  y0 = y0A;
2455
0
  x1 = x1A;
2456
0
  y1 = y1A;
2457
0
  t0 = t0A;
2458
0
  t1 = t1A;
2459
0
  nFuncs = nFuncsA;
2460
0
  for (i = 0; i < nFuncs; ++i) {
2461
0
    funcs[i] = funcsA[i];
2462
0
  }
2463
0
  extend0 = extend0A;
2464
0
  extend1 = extend1A;
2465
0
}
2466
2467
GfxAxialShading::GfxAxialShading(GfxAxialShading *shading):
2468
0
  GfxShading(shading)
2469
0
{
2470
0
  int i;
2471
2472
0
  x0 = shading->x0;
2473
0
  y0 = shading->y0;
2474
0
  x1 = shading->x1;
2475
0
  y1 = shading->y1;
2476
0
  t0 = shading->t0;
2477
0
  t1 = shading->t1;
2478
0
  nFuncs = shading->nFuncs;
2479
0
  for (i = 0; i < nFuncs; ++i) {
2480
0
    funcs[i] = shading->funcs[i]->copy();
2481
0
  }
2482
0
  extend0 = shading->extend0;
2483
0
  extend1 = shading->extend1;
2484
0
}
2485
2486
0
GfxAxialShading::~GfxAxialShading() {
2487
0
  int i;
2488
2489
0
  for (i = 0; i < nFuncs; ++i) {
2490
0
    delete funcs[i];
2491
0
  }
2492
0
}
2493
2494
GfxAxialShading *GfxAxialShading::parse(Dict *dict
2495
0
          ) {
2496
0
  GfxAxialShading *shading;
2497
0
  double x0A, y0A, x1A, y1A;
2498
0
  double t0A, t1A;
2499
0
  Function *funcsA[gfxColorMaxComps];
2500
0
  int nFuncsA;
2501
0
  GBool extend0A, extend1A, ok;
2502
0
  Object obj1, obj2;
2503
0
  int i;
2504
2505
0
  x0A = y0A = x1A = y1A = 0;
2506
0
  if (dict->lookup("Coords", &obj1)->isArray() &&
2507
0
      obj1.arrayGetLength() == 4) {
2508
0
    x0A = obj1.arrayGet(0, &obj2)->getNum();
2509
0
    obj2.free();
2510
0
    y0A = obj1.arrayGet(1, &obj2)->getNum();
2511
0
    obj2.free();
2512
0
    x1A = obj1.arrayGet(2, &obj2)->getNum();
2513
0
    obj2.free();
2514
0
    y1A = obj1.arrayGet(3, &obj2)->getNum();
2515
0
    obj2.free();
2516
0
  } else {
2517
0
    error(errSyntaxError, -1,
2518
0
    "Missing or invalid Coords in shading dictionary");
2519
0
    obj1.free();
2520
0
    goto err1;
2521
0
  }
2522
0
  obj1.free();
2523
2524
0
  t0A = 0;
2525
0
  t1A = 1;
2526
0
  if (dict->lookup("Domain", &obj1)->isArray() &&
2527
0
      obj1.arrayGetLength() == 2) {
2528
0
    t0A = obj1.arrayGet(0, &obj2)->getNum();
2529
0
    obj2.free();
2530
0
    t1A = obj1.arrayGet(1, &obj2)->getNum();
2531
0
    obj2.free();
2532
0
  }
2533
0
  obj1.free();
2534
2535
0
  dict->lookup("Function", &obj1);
2536
0
  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
0
  } else {
2553
0
    nFuncsA = 1;
2554
0
    if (!(funcsA[0] = Function::parse(&obj1, 1, -1))) {
2555
0
      obj1.free();
2556
0
      goto err1;
2557
0
    }
2558
0
  }
2559
0
  obj1.free();
2560
2561
0
  extend0A = extend1A = gFalse;
2562
0
  if (dict->lookup("Extend", &obj1)->isArray() &&
2563
0
      obj1.arrayGetLength() == 2) {
2564
0
    extend0A = obj1.arrayGet(0, &obj2)->getBool();
2565
0
    obj2.free();
2566
0
    extend1A = obj1.arrayGet(1, &obj2)->getBool();
2567
0
    obj2.free();
2568
0
  }
2569
0
  obj1.free();
2570
2571
0
  shading = new GfxAxialShading(x0A, y0A, x1A, y1A, t0A, t1A,
2572
0
        funcsA, nFuncsA, extend0A, extend1A);
2573
0
  if (!shading->init(dict
2574
0
         )) {
2575
0
    delete shading;
2576
0
    return NULL;
2577
0
  }
2578
2579
0
  ok = gFalse;
2580
0
  if (shading->nFuncs == 1) {
2581
0
    ok = shading->funcs[0]->getOutputSize()
2582
0
           == shading->getColorSpace()->getNComps();
2583
0
  } 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
0
  if (!ok) {
2590
0
    error(errSyntaxError, -1, "Invalid function in shading dictionary");
2591
0
    delete shading;
2592
0
    return NULL;
2593
0
  }
2594
2595
0
  return shading;
2596
2597
0
 err1:
2598
0
  return NULL;
2599
0
}
2600
2601
0
GfxShading *GfxAxialShading::copy() {
2602
0
  return new GfxAxialShading(this);
2603
0
}
2604
2605
0
void GfxAxialShading::getColor(double t, GfxColor *color) {
2606
0
  double out[gfxColorMaxComps];
2607
0
  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
0
  for (i = 0; i < gfxColorMaxComps; ++i) {
2612
0
    out[i] = 0;
2613
0
  }
2614
0
  for (i = 0; i < nFuncs; ++i) {
2615
0
    funcs[i]->transform(&t, &out[i]);
2616
0
  }
2617
0
  for (i = 0; i < gfxColorMaxComps; ++i) {
2618
0
    color->c[i] = dblToCol(out[i]);
2619
0
  }
2620
0
}
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
0
GfxShadingBitBuf::GfxShadingBitBuf(Stream *strA) {
2831
0
  str = strA;
2832
0
  str->reset();
2833
0
  bitBuf = 0;
2834
0
  nBits = 0;
2835
0
}
2836
2837
0
GfxShadingBitBuf::~GfxShadingBitBuf() {
2838
0
  str->close();
2839
0
}
2840
2841
0
GBool GfxShadingBitBuf::getBits(int n, Guint *val) {
2842
0
  int x;
2843
2844
0
  if (nBits >= n) {
2845
0
    x = (bitBuf >> (nBits - n)) & ((1 << n) - 1);
2846
0
    nBits -= n;
2847
0
  } else {
2848
0
    x = 0;
2849
0
    if (nBits > 0) {
2850
0
      x = bitBuf & ((1 << nBits) - 1);
2851
0
      n -= nBits;
2852
0
      nBits = 0;
2853
0
    }
2854
0
    while (n > 0) {
2855
0
      if ((bitBuf = str->getChar()) == EOF) {
2856
0
  nBits = 0;
2857
0
  return gFalse;
2858
0
      }
2859
0
      if (n >= 8) {
2860
0
  x = (x << 8) | bitBuf;
2861
0
  n -= 8;
2862
0
      } else {
2863
0
  x = (x << n) | (bitBuf >> (8 - n));
2864
0
  nBits = 8 - n;
2865
0
  n = 0;
2866
0
      }
2867
0
    }
2868
0
  }
2869
0
  *val = x;
2870
0
  return gTrue;
2871
0
}
2872
2873
0
void GfxShadingBitBuf::flushBits() {
2874
0
  bitBuf = 0;
2875
0
  nBits = 0;
2876
0
}
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
0
  GfxShading(typeA)
2888
0
{
2889
0
  int i;
2890
2891
0
  vertices = verticesA;
2892
0
  nVertices = nVerticesA;
2893
0
  triangles = trianglesA;
2894
0
  nTriangles = nTrianglesA;
2895
0
  nComps = nCompsA;
2896
0
  nFuncs = nFuncsA;
2897
0
  for (i = 0; i < nFuncs; ++i) {
2898
0
    funcs[i] = funcsA[i];
2899
0
  }
2900
0
}
2901
2902
GfxGouraudTriangleShading::GfxGouraudTriangleShading(
2903
             GfxGouraudTriangleShading *shading):
2904
0
  GfxShading(shading)
2905
0
{
2906
0
  int i;
2907
2908
0
  nVertices = shading->nVertices;
2909
0
  vertices = (GfxGouraudVertex *)gmallocn(nVertices, sizeof(GfxGouraudVertex));
2910
0
  memcpy(vertices, shading->vertices, nVertices * sizeof(GfxGouraudVertex));
2911
0
  nTriangles = shading->nTriangles;
2912
0
  triangles = (int (*)[3])gmallocn(nTriangles * 3, sizeof(int));
2913
0
  memcpy(triangles, shading->triangles, nTriangles * 3 * sizeof(int));
2914
0
  nComps = shading->nComps;
2915
0
  nFuncs = shading->nFuncs;
2916
0
  for (i = 0; i < nFuncs; ++i) {
2917
0
    funcs[i] = shading->funcs[i]->copy();
2918
0
  }
2919
0
}
2920
2921
0
GfxGouraudTriangleShading::~GfxGouraudTriangleShading() {
2922
0
  int i;
2923
2924
0
  gfree(vertices);
2925
0
  gfree(triangles);
2926
0
  for (i = 0; i < nFuncs; ++i) {
2927
0
    delete funcs[i];
2928
0
  }
2929
0
}
2930
2931
GfxGouraudTriangleShading *GfxGouraudTriangleShading::parse(
2932
             int typeA, Dict *dict, Stream *str
2933
0
             ) {
2934
0
  GfxGouraudTriangleShading *shading;
2935
0
  Function *funcsA[gfxColorMaxComps];
2936
0
  int nFuncsA;
2937
0
  int coordBits, compBits, flagBits, vertsPerRow, nRows;
2938
0
  double xMin, xMax, yMin, yMax;
2939
0
  double cMin[gfxColorMaxComps], cMax[gfxColorMaxComps];
2940
0
  double xMul, yMul;
2941
0
  double cMul[gfxColorMaxComps];
2942
0
  GfxGouraudVertex *verticesA;
2943
0
  int (*trianglesA)[3];
2944
0
  int nCompsA, nVerticesA, nTrianglesA, vertSize, triSize;
2945
0
  Guint x, y, flag;
2946
0
  Guint c[gfxColorMaxComps];
2947
0
  GfxShadingBitBuf *bitBuf;
2948
0
  Object obj1, obj2;
2949
0
  GBool ok;
2950
0
  int i, j, k, state;
2951
2952
0
  if (dict->lookup("BitsPerCoordinate", &obj1)->isInt()) {
2953
0
    coordBits = obj1.getInt();
2954
0
  } else {
2955
0
    error(errSyntaxError, -1,
2956
0
    "Missing or invalid BitsPerCoordinate in shading dictionary");
2957
0
    goto err2;
2958
0
  }
2959
0
  if (coordBits <= 0 || coordBits > 32) {
2960
0
    error(errSyntaxError, -1,
2961
0
    "Invalid BitsPerCoordinate in shading dictionary");
2962
0
    goto err2;
2963
0
  }
2964
0
  obj1.free();
2965
0
  if (dict->lookup("BitsPerComponent", &obj1)->isInt()) {
2966
0
    compBits = obj1.getInt();
2967
0
  } else {
2968
0
    error(errSyntaxError, -1,
2969
0
    "Missing or invalid BitsPerComponent in shading dictionary");
2970
0
    goto err2;
2971
0
  }
2972
0
  if (compBits <= 0 || compBits > 16) {
2973
0
    error(errSyntaxError, -1,
2974
0
    "Invalid BitsPerComponent in shading dictionary");
2975
0
    goto err2;
2976
0
  }
2977
0
  obj1.free();
2978
0
  flagBits = vertsPerRow = 0; // make gcc happy
2979
0
  if (typeA == 4) {
2980
0
    if (dict->lookup("BitsPerFlag", &obj1)->isInt()) {
2981
0
      flagBits = obj1.getInt();
2982
0
    } else {
2983
0
      error(errSyntaxError, -1,
2984
0
      "Missing or invalid BitsPerFlag in shading dictionary");
2985
0
      goto err2;
2986
0
    }
2987
0
    if (flagBits < 2 || flagBits > 8) {
2988
0
      error(errSyntaxError, -1, "Invalid BitsPerFlag in shading dictionary");
2989
0
      goto err2;
2990
0
    }
2991
0
    obj1.free();
2992
0
  } else {
2993
0
    if (dict->lookup("VerticesPerRow", &obj1)->isInt()) {
2994
0
      vertsPerRow = obj1.getInt();
2995
0
    } else {
2996
0
      error(errSyntaxError, -1,
2997
0
      "Missing or invalid VerticesPerRow in shading dictionary");
2998
0
      goto err2;
2999
0
    }
3000
0
    obj1.free();
3001
0
    if (vertsPerRow < 2) {
3002
0
      error(errSyntaxError, -1,
3003
0
      "Invalid VerticesPerRow in shading dictionary");
3004
0
      goto err2;
3005
0
    }
3006
0
  }
3007
0
  if (dict->lookup("Decode", &obj1)->isArray() &&
3008
0
      obj1.arrayGetLength() >= 6) {
3009
0
    xMin = obj1.arrayGet(0, &obj2)->getNum();
3010
0
    obj2.free();
3011
0
    xMax = obj1.arrayGet(1, &obj2)->getNum();
3012
0
    obj2.free();
3013
0
    xMul = (xMax - xMin) / (pow(2.0, coordBits) - 1);
3014
0
    yMin = obj1.arrayGet(2, &obj2)->getNum();
3015
0
    obj2.free();
3016
0
    yMax = obj1.arrayGet(3, &obj2)->getNum();
3017
0
    obj2.free();
3018
0
    yMul = (yMax - yMin) / (pow(2.0, coordBits) - 1);
3019
0
    for (i = 0; 5 + 2*i < obj1.arrayGetLength() && i < gfxColorMaxComps; ++i) {
3020
0
      cMin[i] = obj1.arrayGet(4 + 2*i, &obj2)->getNum();
3021
0
      obj2.free();
3022
0
      cMax[i] = obj1.arrayGet(5 + 2*i, &obj2)->getNum();
3023
0
      obj2.free();
3024
0
      cMul[i] = (cMax[i] - cMin[i]) / (double)((1 << compBits) - 1);
3025
0
    }
3026
0
    nCompsA = i;
3027
0
  } else {
3028
0
    error(errSyntaxError, -1,
3029
0
    "Missing or invalid Decode array in shading dictionary");
3030
0
    goto err2;
3031
0
  }
3032
0
  obj1.free();
3033
3034
0
  if (!dict->lookup("Function", &obj1)->isNull()) {
3035
0
    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
0
    } else {
3052
0
      nFuncsA = 1;
3053
0
      if (!(funcsA[0] = Function::parse(&obj1, 1, -1))) {
3054
0
  obj1.free();
3055
0
  goto err1;
3056
0
      }
3057
0
    }
3058
0
  } else {
3059
0
    nFuncsA = 0;
3060
0
  }
3061
0
  obj1.free();
3062
3063
0
  nVerticesA = nTrianglesA = 0;
3064
0
  verticesA = NULL;
3065
0
  trianglesA = NULL;
3066
0
  vertSize = triSize = 0;
3067
0
  state = 0;
3068
0
  flag = 0; // make gcc happy
3069
0
  bitBuf = new GfxShadingBitBuf(str);
3070
0
  while (1) {
3071
0
    if (typeA == 4) {
3072
0
      if (!bitBuf->getBits(flagBits, &flag)) {
3073
0
  break;
3074
0
      }
3075
0
    }
3076
0
    if (!bitBuf->getBits(coordBits, &x) ||
3077
0
  !bitBuf->getBits(coordBits, &y)) {
3078
0
      break;
3079
0
    }
3080
0
    for (i = 0; i < nCompsA; ++i) {
3081
0
      if (!bitBuf->getBits(compBits, &c[i])) {
3082
0
  break;
3083
0
      }
3084
0
    }
3085
0
    if (i < nCompsA) {
3086
0
      break;
3087
0
    }
3088
0
    if (nVerticesA == vertSize) {
3089
0
      vertSize = (vertSize == 0) ? 16 : 2 * vertSize;
3090
0
      verticesA = (GfxGouraudVertex *)
3091
0
                greallocn(verticesA, vertSize, sizeof(GfxGouraudVertex));
3092
0
    }
3093
0
    verticesA[nVerticesA].x = xMin + xMul * (double)x;
3094
0
    verticesA[nVerticesA].y = yMin + yMul * (double)y;
3095
0
    for (i = 0; i < nCompsA; ++i) {
3096
0
      verticesA[nVerticesA].color[i] = cMin[i] + cMul[i] * (double)c[i];
3097
0
    }
3098
0
    ++nVerticesA;
3099
0
    bitBuf->flushBits();
3100
0
    if (typeA == 4) {
3101
0
      if (state == 0 || state == 1) {
3102
0
  ++state;
3103
0
      } else if (state == 2 || flag > 0) {
3104
0
  if (nTrianglesA == triSize) {
3105
0
    triSize = (triSize == 0) ? 16 : 2 * triSize;
3106
0
    trianglesA = (int (*)[3])
3107
0
                     greallocn(trianglesA, triSize * 3, sizeof(int));
3108
0
  }
3109
0
  if (state == 2) {
3110
0
    trianglesA[nTrianglesA][0] = nVerticesA - 3;
3111
0
    trianglesA[nTrianglesA][1] = nVerticesA - 2;
3112
0
    trianglesA[nTrianglesA][2] = nVerticesA - 1;
3113
0
    ++state;
3114
0
  } else if (flag == 1) {
3115
0
    trianglesA[nTrianglesA][0] = trianglesA[nTrianglesA - 1][1];
3116
0
    trianglesA[nTrianglesA][1] = trianglesA[nTrianglesA - 1][2];
3117
0
    trianglesA[nTrianglesA][2] = nVerticesA - 1;
3118
0
  } else { // flag == 2
3119
0
    trianglesA[nTrianglesA][0] = trianglesA[nTrianglesA - 1][0];
3120
0
    trianglesA[nTrianglesA][1] = trianglesA[nTrianglesA - 1][2];
3121
0
    trianglesA[nTrianglesA][2] = nVerticesA - 1;
3122
0
  }
3123
0
  ++nTrianglesA;
3124
0
      } else { // state == 3 && flag == 0
3125
0
  state = 1;
3126
0
      }
3127
0
    }
3128
0
  }
3129
0
  delete bitBuf;
3130
0
  if (typeA == 5) {
3131
0
    nRows = nVerticesA / vertsPerRow;
3132
0
    if (nRows == 0) {
3133
0
      error(errSyntaxError, -1,
3134
0
      "Invalid VerticesPerRow in shading dictionary");
3135
0
      goto err3;
3136
0
    }
3137
0
    nTrianglesA = (nRows - 1) * 2 * (vertsPerRow - 1);
3138
0
    trianglesA = (int (*)[3])gmallocn(nTrianglesA * 3, sizeof(int));
3139
0
    k = 0;
3140
0
    for (i = 0; i < nRows - 1; ++i) {
3141
0
      for (j = 0; j < vertsPerRow - 1; ++j) {
3142
0
  trianglesA[k][0] = i * vertsPerRow + j;
3143
0
  trianglesA[k][1] = i * vertsPerRow + j+1;
3144
0
  trianglesA[k][2] = (i+1) * vertsPerRow + j;
3145
0
  ++k;
3146
0
  trianglesA[k][0] = i * vertsPerRow + j+1;
3147
0
  trianglesA[k][1] = (i+1) * vertsPerRow + j;
3148
0
  trianglesA[k][2] = (i+1) * vertsPerRow + j+1;
3149
0
  ++k;
3150
0
      }
3151
0
    }
3152
0
  }
3153
3154
0
  shading = new GfxGouraudTriangleShading(typeA, verticesA, nVerticesA,
3155
0
            trianglesA, nTrianglesA,
3156
0
            nCompsA, funcsA, nFuncsA);
3157
0
  if (!shading->init(dict
3158
0
         )) {
3159
0
    delete shading;
3160
0
    return NULL;
3161
0
  }
3162
3163
0
  ok = gFalse;
3164
0
  if (shading->nFuncs == 0) {
3165
0
    ok = shading->nComps == shading->getColorSpace()->getNComps();
3166
0
  } else if (shading->nFuncs == 1) {
3167
0
    ok = shading->funcs[0]->getOutputSize()
3168
0
           == shading->getColorSpace()->getNComps();
3169
0
  } 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
0
  if (!ok) {
3176
0
    error(errSyntaxError, -1, "Invalid function in shading dictionary");
3177
0
    delete shading;
3178
0
    return NULL;
3179
0
  }
3180
3181
0
  return shading;
3182
3183
0
 err3:
3184
0
  gfree(trianglesA);
3185
0
  gfree(verticesA);
3186
0
  for (i = 0; i < nFuncsA; ++i) {
3187
0
    delete funcsA[i];
3188
0
  }
3189
0
 err2:
3190
0
  obj1.free();
3191
0
 err1:
3192
0
  return NULL;
3193
0
}
3194
3195
0
GfxShading *GfxGouraudTriangleShading::copy() {
3196
0
  return new GfxGouraudTriangleShading(this);
3197
0
}
3198
3199
void GfxGouraudTriangleShading::getTriangle(
3200
            int i,
3201
            double *x0, double *y0, double *color0,
3202
            double *x1, double *y1, double *color1,
3203
0
            double *x2, double *y2, double *color2) {
3204
0
  int v, j;
3205
3206
0
  v = triangles[i][0];
3207
0
  *x0 = vertices[v].x;
3208
0
  *y0 = vertices[v].y;
3209
0
  for (j = 0; j < nComps; ++j) {
3210
0
    color0[j] = vertices[v].color[j];
3211
0
  }
3212
0
  v = triangles[i][1];
3213
0
  *x1 = vertices[v].x;
3214
0
  *y1 = vertices[v].y;
3215
0
  for (j = 0; j < nComps; ++j) {
3216
0
    color1[j] = vertices[v].color[j];
3217
0
  }
3218
0
  v = triangles[i][2];
3219
0
  *x2 = vertices[v].x;
3220
0
  *y2 = vertices[v].y;
3221
0
  for (j = 0; j < nComps; ++j) {
3222
0
    color2[j] = vertices[v].color[j];
3223
0
  }
3224
0
}
3225
3226
void GfxGouraudTriangleShading::getBBox(double *xMinA, double *yMinA,
3227
0
          double *xMaxA, double *yMaxA) {
3228
0
  double xxMin = 0;
3229
0
  double yyMin = 0;
3230
0
  double xxMax = 0;
3231
0
  double yyMax = 0;
3232
0
  if (nVertices > 0) {
3233
0
    xxMin = xxMax = vertices[0].x;
3234
0
    yyMin = yyMax = vertices[0].y;
3235
0
  }
3236
0
  for (int i = 1; i < nVertices; ++i) {
3237
0
    if (vertices[i].x < xxMin) {
3238
0
      xxMin = vertices[i].x;
3239
0
    } else if (vertices[i].x > xxMax) {
3240
0
      xxMax = vertices[i].x;
3241
0
    }
3242
0
    if (vertices[i].y < yyMin) {
3243
0
      yyMin = vertices[i].y;
3244
0
    } else if (vertices[i].y > yyMax) {
3245
0
      yyMax = vertices[i].y;
3246
0
    }
3247
0
  }
3248
0
  *xMinA = xxMin;
3249
0
  *yMinA = yyMin;
3250
0
  *xMaxA = xxMax;
3251
0
  *yMaxA = yyMax;
3252
0
}
3253
3254
0
void GfxGouraudTriangleShading::getColor(double *in, GfxColor *out) {
3255
0
  double c[gfxColorMaxComps];
3256
0
  int i;
3257
3258
0
  if (nFuncs > 0) {
3259
0
    for (i = 0; i < nFuncs; ++i) {
3260
0
      funcs[i]->transform(in, &c[i]);
3261
0
    }
3262
0
    for (i = 0; i < colorSpace->getNComps(); ++i) {
3263
0
      out->c[i] = dblToCol(c[i]);
3264
0
    }
3265
0
  } else {
3266
0
    for (i = 0; i < nComps; ++i) {
3267
0
      out->c[i] = dblToCol(in[i]);
3268
0
    }
3269
0
  }
3270
0
}
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
0
  GfxShading(typeA)
3281
0
{
3282
0
  int i;
3283
3284
0
  patches = patchesA;
3285
0
  nPatches = nPatchesA;
3286
0
  nComps = nCompsA;
3287
0
  nFuncs = nFuncsA;
3288
0
  for (i = 0; i < nFuncs; ++i) {
3289
0
    funcs[i] = funcsA[i];
3290
0
  }
3291
0
}
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
0
GfxPatchMeshShading::~GfxPatchMeshShading() {
3309
0
  int i;
3310
3311
0
  gfree(patches);
3312
0
  for (i = 0; i < nFuncs; ++i) {
3313
0
    delete funcs[i];
3314
0
  }
3315
0
}
3316
3317
GfxPatchMeshShading *GfxPatchMeshShading::parse(int typeA, Dict *dict,
3318
            Stream *str
3319
0
            ) {
3320
0
  GfxPatchMeshShading *shading;
3321
0
  Function *funcsA[gfxColorMaxComps];
3322
0
  int nFuncsA;
3323
0
  int coordBits, compBits, flagBits;
3324
0
  double xMin, xMax, yMin, yMax;
3325
0
  double cMin[gfxColorMaxComps], cMax[gfxColorMaxComps];
3326
0
  double xMul, yMul;
3327
0
  double cMul[gfxColorMaxComps];
3328
0
  GfxPatch *patchesA, *p;
3329
0
  int nCompsA, nPatchesA, patchesSize, nPts, nColors;
3330
0
  Guint flag;
3331
0
  double x[16], y[16];
3332
0
  Guint xi, yi;
3333
0
  double c[4][gfxColorMaxComps];
3334
0
  Guint ci;
3335
0
  GfxShadingBitBuf *bitBuf;
3336
0
  Object obj1, obj2;
3337
0
  GBool ok;
3338
0
  int i, j;
3339
3340
0
  nPatchesA = 0;
3341
0
  patchesA = NULL;
3342
0
  patchesSize = 0;
3343
3344
0
  if (dict->lookup("BitsPerCoordinate", &obj1)->isInt()) {
3345
0
    coordBits = obj1.getInt();
3346
0
  } else {
3347
0
    error(errSyntaxError, -1,
3348
0
    "Missing or invalid BitsPerCoordinate in shading dictionary");
3349
0
    goto err2;
3350
0
  }
3351
0
  if (coordBits <= 0 || coordBits > 32) {
3352
0
    error(errSyntaxError, -1,
3353
0
    "Invalid BitsPerCoordinate in shading dictionary");
3354
0
    goto err2;
3355
0
  }
3356
0
  obj1.free();
3357
0
  if (dict->lookup("BitsPerComponent", &obj1)->isInt()) {
3358
0
    compBits = obj1.getInt();
3359
0
  } else {
3360
0
    error(errSyntaxError, -1,
3361
0
    "Missing or invalid BitsPerComponent in shading dictionary");
3362
0
    goto err2;
3363
0
  }
3364
0
  if (compBits <= 0 || compBits > 16) {
3365
0
    error(errSyntaxError, -1,
3366
0
    "Invalid BitsPerComponent in shading dictionary");
3367
0
    goto err2;
3368
0
  }
3369
0
  obj1.free();
3370
0
  if (dict->lookup("BitsPerFlag", &obj1)->isInt()) {
3371
0
    flagBits = obj1.getInt();
3372
0
  } else {
3373
0
    error(errSyntaxError, -1,
3374
0
    "Missing or invalid BitsPerFlag in shading dictionary");
3375
0
    goto err2;
3376
0
  }
3377
0
  if (flagBits < 2 || flagBits > 8) {
3378
0
    error(errSyntaxError, -1, "Invalid BitsPerFlag in shading dictionary");
3379
0
    goto err2;
3380
0
  }
3381
0
  obj1.free();
3382
0
  if (dict->lookup("Decode", &obj1)->isArray() &&
3383
0
      obj1.arrayGetLength() >= 6) {
3384
0
    xMin = obj1.arrayGet(0, &obj2)->getNum();
3385
0
    obj2.free();
3386
0
    xMax = obj1.arrayGet(1, &obj2)->getNum();
3387
0
    obj2.free();
3388
0
    xMul = (xMax - xMin) / (pow(2.0, coordBits) - 1);
3389
0
    yMin = obj1.arrayGet(2, &obj2)->getNum();
3390
0
    obj2.free();
3391
0
    yMax = obj1.arrayGet(3, &obj2)->getNum();
3392
0
    obj2.free();
3393
0
    yMul = (yMax - yMin) / (pow(2.0, coordBits) - 1);
3394
0
    for (i = 0; 5 + 2*i < obj1.arrayGetLength() && i < gfxColorMaxComps; ++i) {
3395
0
      cMin[i] = obj1.arrayGet(4 + 2*i, &obj2)->getNum();
3396
0
      obj2.free();
3397
0
      cMax[i] = obj1.arrayGet(5 + 2*i, &obj2)->getNum();
3398
0
      obj2.free();
3399
0
      cMul[i] = (cMax[i] - cMin[i]) / (double)((1 << compBits) - 1);
3400
0
    }
3401
0
    nCompsA = i;
3402
0
  } else {
3403
0
    error(errSyntaxError, -1,
3404
0
    "Missing or invalid Decode array in shading dictionary");
3405
0
    goto err2;
3406
0
  }
3407
0
  obj1.free();
3408
3409
0
  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
0
  } else {
3434
0
    nFuncsA = 0;
3435
0
  }
3436
0
  obj1.free();
3437
3438
0
  bitBuf = new GfxShadingBitBuf(str);
3439
0
  while (1) {
3440
0
    if (!bitBuf->getBits(flagBits, &flag)) {
3441
0
      break;
3442
0
    }
3443
0
    flag &= 3;
3444
0
    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
0
    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
0
    } else {
3458
0
      switch (flag) {
3459
0
      case 0: nPts = 16; nColors = 4; break;
3460
0
      case 1:
3461
0
      case 2:
3462
0
      case 3:
3463
0
      default: nPts = 12; nColors = 2; break;
3464
0
      }
3465
0
    }
3466
0
    for (i = 0; i < nPts; ++i) {
3467
0
      if (!bitBuf->getBits(coordBits, &xi) ||
3468
0
    !bitBuf->getBits(coordBits, &yi)) {
3469
0
  break;
3470
0
      }
3471
0
      x[i] = xMin + xMul * (double)xi;
3472
0
      y[i] = yMin + yMul * (double)yi;
3473
0
    }
3474
0
    if (i < nPts) {
3475
0
      break;
3476
0
    }
3477
0
    for (i = 0; i < nColors; ++i) {
3478
0
      for (j = 0; j < nCompsA; ++j) {
3479
0
  if (!bitBuf->getBits(compBits, &ci)) {
3480
0
    break;
3481
0
  }
3482
0
  c[i][j] = cMin[j] + cMul[j] * (double)ci;
3483
0
      }
3484
0
      if (j < nCompsA) {
3485
0
  break;
3486
0
      }
3487
0
    }
3488
0
    if (i < nColors) {
3489
0
      break;
3490
0
    }
3491
0
    if (nPatchesA == patchesSize) {
3492
0
      patchesSize = (patchesSize == 0) ? 16 : 2 * patchesSize;
3493
0
      patchesA = (GfxPatch *)greallocn(patchesA,
3494
0
               patchesSize, sizeof(GfxPatch));
3495
0
    }
3496
0
    p = &patchesA[nPatchesA];
3497
0
    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
0
    } else {
3629
0
      switch (flag) {
3630
0
      case 0:
3631
0
  p->x[0][0] = x[0];
3632
0
  p->y[0][0] = y[0];
3633
0
  p->x[0][1] = x[1];
3634
0
  p->y[0][1] = y[1];
3635
0
  p->x[0][2] = x[2];
3636
0
  p->y[0][2] = y[2];
3637
0
  p->x[0][3] = x[3];
3638
0
  p->y[0][3] = y[3];
3639
0
  p->x[1][3] = x[4];
3640
0
  p->y[1][3] = y[4];
3641
0
  p->x[2][3] = x[5];
3642
0
  p->y[2][3] = y[5];
3643
0
  p->x[3][3] = x[6];
3644
0
  p->y[3][3] = y[6];
3645
0
  p->x[3][2] = x[7];
3646
0
  p->y[3][2] = y[7];
3647
0
  p->x[3][1] = x[8];
3648
0
  p->y[3][1] = y[8];
3649
0
  p->x[3][0] = x[9];
3650
0
  p->y[3][0] = y[9];
3651
0
  p->x[2][0] = x[10];
3652
0
  p->y[2][0] = y[10];
3653
0
  p->x[1][0] = x[11];
3654
0
  p->y[1][0] = y[11];
3655
0
  p->x[1][1] = x[12];
3656
0
  p->y[1][1] = y[12];
3657
0
  p->x[1][2] = x[13];
3658
0
  p->y[1][2] = y[13];
3659
0
  p->x[2][2] = x[14];
3660
0
  p->y[2][2] = y[14];
3661
0
  p->x[2][1] = x[15];
3662
0
  p->y[2][1] = y[15];
3663
0
  for (j = 0; j < nCompsA; ++j) {
3664
0
    p->color[0][0][j] = c[0][j];
3665
0
    p->color[0][1][j] = c[1][j];
3666
0
    p->color[1][1][j] = c[2][j];
3667
0
    p->color[1][0][j] = c[3][j];
3668
0
  }
3669
0
  break;
3670
0
      case 1:
3671
0
  p->x[0][0] = patchesA[nPatchesA-1].x[0][3];
3672
0
  p->y[0][0] = patchesA[nPatchesA-1].y[0][3];
3673
0
  p->x[0][1] = patchesA[nPatchesA-1].x[1][3];
3674
0
  p->y[0][1] = patchesA[nPatchesA-1].y[1][3];
3675
0
  p->x[0][2] = patchesA[nPatchesA-1].x[2][3];
3676
0
  p->y[0][2] = patchesA[nPatchesA-1].y[2][3];
3677
0
  p->x[0][3] = patchesA[nPatchesA-1].x[3][3];
3678
0
  p->y[0][3] = patchesA[nPatchesA-1].y[3][3];
3679
0
  p->x[1][3] = x[0];
3680
0
  p->y[1][3] = y[0];
3681
0
  p->x[2][3] = x[1];
3682
0
  p->y[2][3] = y[1];
3683
0
  p->x[3][3] = x[2];
3684
0
  p->y[3][3] = y[2];
3685
0
  p->x[3][2] = x[3];
3686
0
  p->y[3][2] = y[3];
3687
0
  p->x[3][1] = x[4];
3688
0
  p->y[3][1] = y[4];
3689
0
  p->x[3][0] = x[5];
3690
0
  p->y[3][0] = y[5];
3691
0
  p->x[2][0] = x[6];
3692
0
  p->y[2][0] = y[6];
3693
0
  p->x[1][0] = x[7];
3694
0
  p->y[1][0] = y[7];
3695
0
  p->x[1][1] = x[8];
3696
0
  p->y[1][1] = y[8];
3697
0
  p->x[1][2] = x[9];
3698
0
  p->y[1][2] = y[9];
3699
0
  p->x[2][2] = x[10];
3700
0
  p->y[2][2] = y[10];
3701
0
  p->x[2][1] = x[11];
3702
0
  p->y[2][1] = y[11];
3703
0
  for (j = 0; j < nCompsA; ++j) {
3704
0
    p->color[0][0][j] = patchesA[nPatchesA-1].color[0][1][j];
3705
0
    p->color[0][1][j] = patchesA[nPatchesA-1].color[1][1][j];
3706
0
    p->color[1][1][j] = c[0][j];
3707
0
    p->color[1][0][j] = c[1][j];
3708
0
  }
3709
0
  break;
3710
0
      case 2:
3711
0
  p->x[0][0] = patchesA[nPatchesA-1].x[3][3];
3712
0
  p->y[0][0] = patchesA[nPatchesA-1].y[3][3];
3713
0
  p->x[0][1] = patchesA[nPatchesA-1].x[3][2];
3714
0
  p->y[0][1] = patchesA[nPatchesA-1].y[3][2];
3715
0
  p->x[0][2] = patchesA[nPatchesA-1].x[3][1];
3716
0
  p->y[0][2] = patchesA[nPatchesA-1].y[3][1];
3717
0
  p->x[0][3] = patchesA[nPatchesA-1].x[3][0];
3718
0
  p->y[0][3] = patchesA[nPatchesA-1].y[3][0];
3719
0
  p->x[1][3] = x[0];
3720
0
  p->y[1][3] = y[0];
3721
0
  p->x[2][3] = x[1];
3722
0
  p->y[2][3] = y[1];
3723
0
  p->x[3][3] = x[2];
3724
0
  p->y[3][3] = y[2];
3725
0
  p->x[3][2] = x[3];
3726
0
  p->y[3][2] = y[3];
3727
0
  p->x[3][1] = x[4];
3728
0
  p->y[3][1] = y[4];
3729
0
  p->x[3][0] = x[5];
3730
0
  p->y[3][0] = y[5];
3731
0
  p->x[2][0] = x[6];
3732
0
  p->y[2][0] = y[6];
3733
0
  p->x[1][0] = x[7];
3734
0
  p->y[1][0] = y[7];
3735
0
  p->x[1][1] = x[8];
3736
0
  p->y[1][1] = y[8];
3737
0
  p->x[1][2] = x[9];
3738
0
  p->y[1][2] = y[9];
3739
0
  p->x[2][2] = x[10];
3740
0
  p->y[2][2] = y[10];
3741
0
  p->x[2][1] = x[11];
3742
0
  p->y[2][1] = y[11];
3743
0
  for (j = 0; j < nCompsA; ++j) {
3744
0
    p->color[0][0][j] = patchesA[nPatchesA-1].color[1][1][j];
3745
0
    p->color[0][1][j] = patchesA[nPatchesA-1].color[1][0][j];
3746
0
    p->color[1][1][j] = c[0][j];
3747
0
    p->color[1][0][j] = c[1][j];
3748
0
  }
3749
0
  break;
3750
0
      case 3:
3751
0
  p->x[0][0] = patchesA[nPatchesA-1].x[3][0];
3752
0
  p->y[0][0] = patchesA[nPatchesA-1].y[3][0];
3753
0
  p->x[0][1] = patchesA[nPatchesA-1].x[2][0];
3754
0
  p->y[0][1] = patchesA[nPatchesA-1].y[2][0];
3755
0
  p->x[0][2] = patchesA[nPatchesA-1].x[1][0];
3756
0
  p->y[0][2] = patchesA[nPatchesA-1].y[1][0];
3757
0
  p->x[0][3] = patchesA[nPatchesA-1].x[0][0];
3758
0
  p->y[0][3] = patchesA[nPatchesA-1].y[0][0];
3759
0
  p->x[1][3] = x[0];
3760
0
  p->y[1][3] = y[0];
3761
0
  p->x[2][3] = x[1];
3762
0
  p->y[2][3] = y[1];
3763
0
  p->x[3][3] = x[2];
3764
0
  p->y[3][3] = y[2];
3765
0
  p->x[3][2] = x[3];
3766
0
  p->y[3][2] = y[3];
3767
0
  p->x[3][1] = x[4];
3768
0
  p->y[3][1] = y[4];
3769
0
  p->x[3][0] = x[5];
3770
0
  p->y[3][0] = y[5];
3771
0
  p->x[2][0] = x[6];
3772
0
  p->y[2][0] = y[6];
3773
0
  p->x[1][0] = x[7];
3774
0
  p->y[1][0] = y[7];
3775
0
  p->x[1][1] = x[8];
3776
0
  p->y[1][1] = y[8];
3777
0
  p->x[1][2] = x[9];
3778
0
  p->y[1][2] = y[9];
3779
0
  p->x[2][2] = x[10];
3780
0
  p->y[2][2] = y[10];
3781
0
  p->x[2][1] = x[11];
3782
0
  p->y[2][1] = y[11];
3783
0
  for (j = 0; j < nCompsA; ++j) {
3784
0
    p->color[0][0][j] = patchesA[nPatchesA-1].color[1][0][j];
3785
0
    p->color[0][1][j] = patchesA[nPatchesA-1].color[0][0][j];
3786
0
    p->color[1][1][j] = c[0][j];
3787
0
    p->color[1][0][j] = c[1][j];
3788
0
  }
3789
0
  break;
3790
0
      }
3791
0
    }
3792
0
    ++nPatchesA;
3793
0
    bitBuf->flushBits();
3794
0
  }
3795
0
  delete bitBuf;
3796
3797
0
  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
0
  shading = new GfxPatchMeshShading(typeA, patchesA, nPatchesA,
3844
0
            nCompsA, funcsA, nFuncsA);
3845
0
  if (!shading->init(dict
3846
0
         )) {
3847
0
    delete shading;
3848
0
    return NULL;
3849
0
  }
3850
3851
0
  ok = gFalse;
3852
0
  if (shading->nFuncs == 0) {
3853
0
    ok = shading->nComps == shading->getColorSpace()->getNComps();
3854
0
  } 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
0
  if (!ok) {
3864
0
    error(errSyntaxError, -1, "Invalid function in shading dictionary");
3865
0
    delete shading;
3866
0
    return NULL;
3867
0
  }
3868
3869
0
  return shading;
3870
3871
0
 err2:
3872
0
  obj1.free();
3873
0
 err1:
3874
0
  if (patchesA) {
3875
0
    gfree(patchesA);
3876
0
  }
3877
0
  return NULL;
3878
0
}
3879
3880
0
GfxShading *GfxPatchMeshShading::copy() {
3881
0
  return new GfxPatchMeshShading(this);
3882
0
}
3883
3884
void GfxPatchMeshShading::getBBox(double *xMinA, double *yMinA,
3885
0
          double *xMaxA, double *yMaxA) {
3886
0
  double xxMin = 0;
3887
0
  double yyMin = 0;
3888
0
  double xxMax = 0;
3889
0
  double yyMax = 0;
3890
0
  if (nPatches > 0) {
3891
0
    xxMin = patches[0].x[0][0];
3892
0
    yyMin = patches[0].y[0][0];
3893
0
  }
3894
0
  for (int i = 0; i < nPatches; ++i) {
3895
0
    for (int j = 0; j < 4; ++j) {
3896
0
      for (int k = 0; k < 4; ++k) {
3897
0
  if (patches[i].x[j][k] < xxMin) {
3898
0
    xxMin = patches[i].x[j][k];
3899
0
  } else if (patches[i].x[j][k] > xxMax) {
3900
0
    xxMax = patches[i].x[j][k];
3901
0
  }
3902
0
  if (patches[i].y[j][k] < yyMin) {
3903
0
    yyMin = patches[i].y[j][k];
3904
0
  } else if (patches[i].y[j][k] > yyMax) {
3905
0
    yyMax = patches[i].y[j][k];
3906
0
  }
3907
0
      }
3908
0
    }
3909
0
  }
3910
0
  *xMinA = xxMin;
3911
0
  *yMinA = yyMin;
3912
0
  *xMaxA = xxMax;
3913
0
  *yMaxA = yyMax;
3914
0
}
3915
3916
0
void GfxPatchMeshShading::getColor(double *in, GfxColor *out) {
3917
0
  double c[gfxColorMaxComps];
3918
0
  int i;
3919
3920
0
  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
0
  } else {
3928
0
    for (i = 0; i < nComps; ++i) {
3929
0
      out->c[i] = dblToCol(in[i]);
3930
0
    }
3931
0
  }
3932
0
}
3933
3934
//------------------------------------------------------------------------
3935
// GfxImageColorMap
3936
//------------------------------------------------------------------------
3937
3938
GfxImageColorMap::GfxImageColorMap(int bitsA, Object *decode,
3939
           GfxColorSpace *colorSpaceA,
3940
0
           int maxAllowedBits) {
3941
0
  GfxIndexedColorSpace *indexedCS;
3942
0
  GfxSeparationColorSpace *sepCS;
3943
0
  int maxPixel, indexHigh;
3944
0
  Guchar *indexedLookup;
3945
0
  Function *sepFunc;
3946
0
  Object obj;
3947
0
  double defaultLow[gfxColorMaxComps], defaultRange[gfxColorMaxComps];
3948
0
  double x[gfxColorMaxComps], y[gfxColorMaxComps];
3949
0
  int i, j, k;
3950
3951
0
  ok = gTrue;
3952
3953
  // bits per component and color space
3954
0
  bits = bitsA;
3955
0
  if (bits <= maxAllowedBits) {
3956
0
    maxPixel = (1 << bits) - 1;
3957
0
  } else {
3958
0
    maxPixel = (1 << maxAllowedBits) - 1;
3959
0
  }
3960
0
  colorSpace = colorSpaceA;
3961
3962
  // initialize
3963
0
  for (k = 0; k < gfxColorMaxComps; ++k) {
3964
0
    lookup[k] = NULL;
3965
0
    lookup2[k] = NULL;
3966
0
  }
3967
3968
  // get decode map
3969
0
  colorSpace->getDefaultRanges(defaultLow, defaultRange, maxPixel);
3970
0
  if (decode->isNull()) {
3971
0
    nComps = colorSpace->getNComps();
3972
0
    for (i = 0; i < nComps; ++i) {
3973
0
      decodeLow[i] = defaultLow[i];
3974
0
      decodeRange[i] = defaultRange[i];
3975
0
    }
3976
0
  } else if (decode->isArray()) {
3977
0
    nComps = decode->arrayGetLength() / 2;
3978
0
    if (nComps < colorSpace->getNComps()) {
3979
0
      goto err1;
3980
0
    }
3981
0
    if (nComps > colorSpace->getNComps()) {
3982
0
      error(errSyntaxWarning, -1, "Too many elements in Decode array");
3983
0
      nComps = colorSpace->getNComps();
3984
0
    }
3985
0
    for (i = 0; i < nComps; ++i) {
3986
0
      decode->arrayGet(2*i, &obj);
3987
0
      if (!obj.isNum()) {
3988
0
  goto err2;
3989
0
      }
3990
0
      decodeLow[i] = obj.getNum();
3991
0
      obj.free();
3992
0
      decode->arrayGet(2*i+1, &obj);
3993
0
      if (!obj.isNum()) {
3994
0
  goto err2;
3995
0
      }
3996
0
      decodeRange[i] = obj.getNum() - decodeLow[i];
3997
0
      obj.free();
3998
0
    }
3999
0
  } else {
4000
0
    goto err1;
4001
0
  }
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
0
  for (k = 0; k < nComps; ++k) {
4007
0
    lookup[k] = (GfxColorComp *)gmallocn(maxPixel + 1,
4008
0
           sizeof(GfxColorComp));
4009
0
    for (i = 0; i <= maxPixel; ++i) {
4010
0
      double t = decodeLow[k] + (i * decodeRange[k]) / maxPixel;
4011
0
      if (t < defaultLow[k]) {
4012
0
  t = defaultLow[k];
4013
0
      } else if (t > defaultLow[k] + defaultRange[k]) {
4014
0
  t = defaultLow[k] + defaultRange[k];
4015
0
      }
4016
0
      lookup[k][i] = dblToCol(t);
4017
0
    }
4018
0
  }
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
0
  colorSpace2 = NULL;
4024
0
  nComps2 = 0;
4025
0
  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
0
    indexedCS = (GfxIndexedColorSpace *)colorSpace;
4030
0
    colorSpace2 = indexedCS->getBase();
4031
0
    indexHigh = indexedCS->getIndexHigh();
4032
0
    nComps2 = colorSpace2->getNComps();
4033
0
    indexedLookup = indexedCS->getLookup();
4034
0
    colorSpace2->getDefaultRanges(x, y, indexHigh);
4035
0
    for (k = 0; k < nComps2; ++k) {
4036
0
      lookup2[k] = (GfxColorComp *)gmallocn(maxPixel + 1,
4037
0
              sizeof(GfxColorComp));
4038
0
    }
4039
0
    for (i = 0; i <= maxPixel; ++i) {
4040
0
      j = (int)(decodeLow[0] + (i * decodeRange[0]) / maxPixel + 0.5);
4041
0
      if (j < 0) {
4042
0
  j = 0;
4043
0
      } else if (j > indexHigh) {
4044
0
  j = indexHigh;
4045
0
      }
4046
0
      for (k = 0; k < nComps2; ++k) {
4047
0
  lookup2[k][i] =
4048
0
      dblToCol(x[k] + (indexedLookup[j*nComps2 + k] / 255.0) * y[k]);
4049
0
      }
4050
0
    }
4051
0
  } else if (colorSpace->getMode() == csSeparation) {
4052
0
    sepCS = (GfxSeparationColorSpace *)colorSpace;
4053
0
    colorSpace2 = sepCS->getAlt();
4054
0
    nComps2 = colorSpace2->getNComps();
4055
0
    sepFunc = sepCS->getFunc();
4056
0
    for (k = 0; k < nComps2; ++k) {
4057
0
      lookup2[k] = (GfxColorComp *)gmallocn(maxPixel + 1,
4058
0
              sizeof(GfxColorComp));
4059
0
    }
4060
0
    for (i = 0; i <= maxPixel; ++i) {
4061
0
      double t = decodeLow[0] + (i * decodeRange[0]) / maxPixel;
4062
0
      if (t < defaultLow[0]) {
4063
0
  t = defaultLow[0];
4064
0
      } else if (t > defaultLow[0] + defaultRange[0]) {
4065
0
  t = defaultLow[0] + defaultRange[0];
4066
0
      }
4067
0
      x[0] = t;
4068
0
      sepFunc->transform(x, y);
4069
0
      for (k = 0; k < nComps2; ++k) {
4070
0
  lookup2[k][i] = dblToCol(y[k]);
4071
0
      }
4072
0
    }
4073
0
  }
4074
4075
0
  return;
4076
4077
0
 err2:
4078
0
  obj.free();
4079
0
 err1:
4080
0
  ok = gFalse;
4081
0
}
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
0
GfxImageColorMap::~GfxImageColorMap() {
4125
0
  int i;
4126
4127
0
  delete colorSpace;
4128
0
  for (i = 0; i < gfxColorMaxComps; ++i) {
4129
0
    gfree(lookup[i]);
4130
0
    gfree(lookup2[i]);
4131
0
  }
4132
0
}
4133
4134
void GfxImageColorMap::getGray(Guchar *x, GfxGray *gray,
4135
0
             GfxRenderingIntent ri) {
4136
0
  GfxColor color;
4137
0
  int i;
4138
4139
0
  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
0
  } else {
4145
0
    for (i = 0; i < nComps; ++i) {
4146
0
      color.c[i] = lookup[i][x[i]];
4147
0
    }
4148
0
    colorSpace->getGray(&color, gray, ri);
4149
0
  }
4150
0
}
4151
4152
0
void GfxImageColorMap::getRGB(Guchar *x, GfxRGB *rgb, GfxRenderingIntent ri) {
4153
0
  GfxColor color;
4154
0
  int i;
4155
4156
0
  if (colorSpace2) {
4157
0
    for (i = 0; i < nComps2; ++i) {
4158
0
      color.c[i] = lookup2[i][x[0]];
4159
0
    }
4160
0
    colorSpace2->getRGB(&color, rgb, ri);
4161
0
  } else {
4162
0
    for (i = 0; i < nComps; ++i) {
4163
0
      color.c[i] = lookup[i][x[i]];
4164
0
    }
4165
0
    colorSpace->getRGB(&color, rgb, ri);
4166
0
  }
4167
0
}
4168
4169
void GfxImageColorMap::getCMYK(Guchar *x, GfxCMYK *cmyk,
4170
0
             GfxRenderingIntent ri) {
4171
0
  GfxColor color;
4172
0
  int i;
4173
4174
0
  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
0
  } else {
4180
0
    for (i = 0; i < nComps; ++i) {
4181
0
      color.c[i] = lookup[i][x[i]];
4182
0
    }
4183
0
    colorSpace->getCMYK(&color, cmyk, ri);
4184
0
  }
4185
0
}
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
0
              GfxRenderingIntent ri) {
4223
0
  GfxColor color;
4224
0
  GfxRGB rgb;
4225
0
  int i, j;
4226
4227
0
  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
0
  } else {
4238
0
    for (j = 0; j < n; ++j) {
4239
0
      for (i = 0; i < nComps; ++i) {
4240
0
  color.c[i] = lookup[i][in[j * nComps + i]];
4241
0
      }
4242
0
      colorSpace->getRGB(&color, &rgb, ri);
4243
0
      out[j*3] = colToByte(rgb.r);
4244
0
      out[j*3 + 1] = colToByte(rgb.g);
4245
0
      out[j*3 + 2] = colToByte(rgb.b);
4246
0
    }
4247
0
  }
4248
0
}
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
0
GfxSubpath::GfxSubpath(double x1, double y1) {
4287
0
  size = 16;
4288
0
  x = (double *)gmallocn(size, sizeof(double));
4289
0
  y = (double *)gmallocn(size, sizeof(double));
4290
0
  curve = (GBool *)gmallocn(size, sizeof(GBool));
4291
0
  n = 1;
4292
0
  x[0] = x1;
4293
0
  y[0] = y1;
4294
0
  curve[0] = gFalse;
4295
0
  closed = gFalse;
4296
0
}
4297
4298
0
GfxSubpath::~GfxSubpath() {
4299
0
  gfree(x);
4300
0
  gfree(y);
4301
0
  gfree(curve);
4302
0
}
4303
4304
// Used for copy().
4305
0
GfxSubpath::GfxSubpath(GfxSubpath *subpath) {
4306
0
  size = subpath->size;
4307
0
  n = subpath->n;
4308
0
  x = (double *)gmallocn(size, sizeof(double));
4309
0
  y = (double *)gmallocn(size, sizeof(double));
4310
0
  curve = (GBool *)gmallocn(size, sizeof(GBool));
4311
0
  memcpy(x, subpath->x, n * sizeof(double));
4312
0
  memcpy(y, subpath->y, n * sizeof(double));
4313
0
  memcpy(curve, subpath->curve, n * sizeof(GBool));
4314
0
  closed = subpath->closed;
4315
0
}
4316
4317
0
void GfxSubpath::lineTo(double x1, double y1) {
4318
0
  if (n >= size) {
4319
0
    size *= 2;
4320
0
    x = (double *)greallocn(x, size, sizeof(double));
4321
0
    y = (double *)greallocn(y, size, sizeof(double));
4322
0
    curve = (GBool *)greallocn(curve, size, sizeof(GBool));
4323
0
  }
4324
0
  x[n] = x1;
4325
0
  y[n] = y1;
4326
0
  curve[n] = gFalse;
4327
0
  ++n;
4328
0
}
4329
4330
void GfxSubpath::curveTo(double x1, double y1, double x2, double y2,
4331
0
       double x3, double y3) {
4332
0
  if (n+3 > size) {
4333
0
    size *= 2;
4334
0
    x = (double *)greallocn(x, size, sizeof(double));
4335
0
    y = (double *)greallocn(y, size, sizeof(double));
4336
0
    curve = (GBool *)greallocn(curve, size, sizeof(GBool));
4337
0
  }
4338
0
  x[n] = x1;
4339
0
  y[n] = y1;
4340
0
  x[n+1] = x2;
4341
0
  y[n+1] = y2;
4342
0
  x[n+2] = x3;
4343
0
  y[n+2] = y3;
4344
0
  curve[n] = curve[n+1] = gTrue;
4345
0
  curve[n+2] = gFalse;
4346
0
  n += 3;
4347
0
}
4348
4349
0
void GfxSubpath::close() {
4350
0
  if (x[n-1] != x[0] || y[n-1] != y[0]) {
4351
0
    lineTo(x[0], y[0]);
4352
0
  }
4353
0
  closed = gTrue;
4354
0
}
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
0
GfxPath::GfxPath() {
4366
0
  justMoved = gFalse;
4367
0
  size = 16;
4368
0
  n = 0;
4369
0
  firstX = firstY = 0;
4370
0
  subpaths = (GfxSubpath **)gmallocn(size, sizeof(GfxSubpath *));
4371
0
}
4372
4373
0
GfxPath::~GfxPath() {
4374
0
  int i;
4375
4376
0
  for (i = 0; i < n; ++i)
4377
0
    delete subpaths[i];
4378
0
  gfree(subpaths);
4379
0
}
4380
4381
// Used for copy().
4382
GfxPath::GfxPath(GBool justMoved1, double firstX1, double firstY1,
4383
0
     GfxSubpath **subpaths1, int n1, int size1) {
4384
0
  int i;
4385
4386
0
  justMoved = justMoved1;
4387
0
  firstX = firstX1;
4388
0
  firstY = firstY1;
4389
0
  size = size1;
4390
0
  n = n1;
4391
0
  subpaths = (GfxSubpath **)gmallocn(size, sizeof(GfxSubpath *));
4392
0
  for (i = 0; i < n; ++i)
4393
0
    subpaths[i] = subpaths1[i]->copy();
4394
0
}
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
0
void GfxPath::moveTo(double x, double y) {
4417
0
  justMoved = gTrue;
4418
0
  firstX = x;
4419
0
  firstY = y;
4420
0
}
4421
4422
0
void GfxPath::lineTo(double x, double y) {
4423
0
  if (justMoved || (n > 0 && subpaths[n-1]->isClosed())) {
4424
0
    if (n >= size) {
4425
0
      size *= 2;
4426
0
      subpaths = (GfxSubpath **)
4427
0
             greallocn(subpaths, size, sizeof(GfxSubpath *));
4428
0
    }
4429
0
    if (justMoved) {
4430
0
      subpaths[n] = new GfxSubpath(firstX, firstY);
4431
0
    } else {
4432
0
      subpaths[n] = new GfxSubpath(subpaths[n-1]->getLastX(),
4433
0
           subpaths[n-1]->getLastY());
4434
0
    }
4435
0
    ++n;
4436
0
    justMoved = gFalse;
4437
0
  }
4438
0
  subpaths[n-1]->lineTo(x, y);
4439
0
}
4440
4441
void GfxPath::curveTo(double x1, double y1, double x2, double y2,
4442
0
       double x3, double y3) {
4443
0
  if (justMoved || (n > 0 && subpaths[n-1]->isClosed())) {
4444
0
    if (n >= size) {
4445
0
      size *= 2;
4446
0
      subpaths = (GfxSubpath **)
4447
0
             greallocn(subpaths, size, sizeof(GfxSubpath *));
4448
0
    }
4449
0
    if (justMoved) {
4450
0
      subpaths[n] = new GfxSubpath(firstX, firstY);
4451
0
    } else {
4452
0
      subpaths[n] = new GfxSubpath(subpaths[n-1]->getLastX(),
4453
0
           subpaths[n-1]->getLastY());
4454
0
    }
4455
0
    ++n;
4456
0
    justMoved = gFalse;
4457
0
  }
4458
0
  subpaths[n-1]->curveTo(x1, y1, x2, y2, x3, y3);
4459
0
}
4460
4461
0
void GfxPath::close() {
4462
  // this is necessary to handle the pathological case of
4463
  // moveto/closepath/clip, which defines an empty clipping region
4464
0
  if (justMoved) {
4465
0
    if (n >= size) {
4466
0
      size *= 2;
4467
0
      subpaths = (GfxSubpath **)
4468
0
             greallocn(subpaths, size, sizeof(GfxSubpath *));
4469
0
    }
4470
0
    subpaths[n] = new GfxSubpath(firstX, firstY);
4471
0
    ++n;
4472
0
    justMoved = gFalse;
4473
0
  }
4474
0
  subpaths[n-1]->close();
4475
0
}
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
0
       ) {
4507
0
  double kx, ky;
4508
4509
0
  localParams = localParamsA;
4510
0
  hDPI = hDPIA;
4511
0
  vDPI = vDPIA;
4512
0
  rotate = rotateA;
4513
0
  px1 = pageBox->x1;
4514
0
  py1 = pageBox->y1;
4515
0
  px2 = pageBox->x2;
4516
0
  py2 = pageBox->y2;
4517
0
  kx = hDPI / 72.0;
4518
0
  ky = vDPI / 72.0;
4519
0
  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
0
  } 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
0
  } 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
0
  } else {
4547
0
    ctm[0] = kx;
4548
0
    ctm[1] = 0;
4549
0
    ctm[2] = 0;
4550
0
    ctm[3] = upsideDown ? -ky : ky;
4551
0
    ctm[4] = -kx * px1;
4552
0
    ctm[5] = ky * (upsideDown ? py2 : -py1);
4553
0
    pageWidth = kx * (px2 - px1);
4554
0
    pageHeight = ky * (py2 - py1);
4555
0
  }
4556
4557
0
  fillColorSpace = GfxColorSpace::create(csDeviceGray);
4558
0
  strokeColorSpace = GfxColorSpace::create(csDeviceGray);
4559
0
  fillColor.c[0] = 0;
4560
0
  strokeColor.c[0] = 0;
4561
0
  fillPattern = NULL;
4562
0
  strokePattern = NULL;
4563
0
  blendMode = gfxBlendNormal;
4564
0
  fillOpacity = 1;
4565
0
  strokeOpacity = 1;
4566
0
  fillOverprint = gFalse;
4567
0
  strokeOverprint = gFalse;
4568
0
  if (localParams) {
4569
0
    renderingIntent = localParams->getDefaultRenderingIntent();
4570
0
  } else {
4571
0
    renderingIntent = gfxRenderingIntentRelativeColorimetric;
4572
0
  }
4573
0
  overprintMode = 0;
4574
0
  transfer[0] = transfer[1] = transfer[2] = transfer[3] = NULL;
4575
4576
0
  lineWidth = 1;
4577
0
  lineDash = NULL;
4578
0
  lineDashLength = 0;
4579
0
  lineDashStart = 0;
4580
0
  flatness = 1;
4581
0
  lineJoin = 0;
4582
0
  lineCap = 0;
4583
0
  miterLimit = 10;
4584
0
  strokeAdjust = gFalse;
4585
0
  alphaIsShape = gFalse;
4586
4587
0
  font = NULL;
4588
0
  fontSize = 0;
4589
0
  textMat[0] = 1; textMat[1] = 0;
4590
0
  textMat[2] = 0; textMat[3] = 1;
4591
0
  textMat[4] = 0; textMat[5] = 0;
4592
0
  charSpace = 0;
4593
0
  wordSpace = 0;
4594
0
  horizScaling = 1;
4595
0
  leading = 0;
4596
0
  rise = 0;
4597
0
  render = 0;
4598
4599
0
  path = new GfxPath();
4600
0
  curX = curY = 0;
4601
0
  lineX = lineY = 0;
4602
4603
0
  clipXMin = 0;
4604
0
  clipYMin = 0;
4605
0
  clipXMax = pageWidth;
4606
0
  clipYMax = pageHeight;
4607
4608
0
  ignoreColorOps = gFalse;
4609
4610
0
  saved = NULL;
4611
0
}
4612
4613
0
GfxState::~GfxState() {
4614
0
  int i;
4615
4616
0
  if (fillColorSpace) {
4617
0
    delete fillColorSpace;
4618
0
  }
4619
0
  if (strokeColorSpace) {
4620
0
    delete strokeColorSpace;
4621
0
  }
4622
0
  if (fillPattern) {
4623
0
    delete fillPattern;
4624
0
  }
4625
0
  if (strokePattern) {
4626
0
    delete strokePattern;
4627
0
  }
4628
0
  for (i = 0; i < 4; ++i) {
4629
0
    if (transfer[i]) {
4630
0
      delete transfer[i];
4631
0
    }
4632
0
  }
4633
0
  gfree(lineDash);
4634
0
  if (path) {
4635
    // this gets set to NULL by restore()
4636
0
    delete path;
4637
0
  }
4638
0
}
4639
4640
// Used for copy();
4641
0
GfxState::GfxState(GfxState *state, GBool copyPath) {
4642
0
  int i;
4643
4644
0
  memcpy(this, state, sizeof(GfxState));
4645
0
  if (fillColorSpace) {
4646
0
    fillColorSpace = state->fillColorSpace->copy();
4647
0
  }
4648
0
  if (strokeColorSpace) {
4649
0
    strokeColorSpace = state->strokeColorSpace->copy();
4650
0
  }
4651
0
  if (fillPattern) {
4652
0
    fillPattern = state->fillPattern->copy();
4653
0
  }
4654
0
  if (strokePattern) {
4655
0
    strokePattern = state->strokePattern->copy();
4656
0
  }
4657
0
  for (i = 0; i < 4; ++i) {
4658
0
    if (transfer[i]) {
4659
0
      transfer[i] = state->transfer[i]->copy();
4660
0
    }
4661
0
  }
4662
0
  if (lineDashLength > 0) {
4663
0
    lineDash = (double *)gmallocn(lineDashLength, sizeof(double));
4664
0
    memcpy(lineDash, state->lineDash, lineDashLength * sizeof(double));
4665
0
  }
4666
0
  if (copyPath) {
4667
0
    path = state->path->copy();
4668
0
  }
4669
0
  saved = NULL;
4670
0
}
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
0
          double d, double e, double f) {
4766
0
  int i;
4767
4768
0
  ctm[0] = a;
4769
0
  ctm[1] = b;
4770
0
  ctm[2] = c;
4771
0
  ctm[3] = d;
4772
0
  ctm[4] = e;
4773
0
  ctm[5] = f;
4774
4775
  // avoid FP exceptions on badly messed up PDF files
4776
0
  for (i = 0; i < 6; ++i) {
4777
0
    if (ctm[i] > 1e10) {
4778
0
      ctm[i] = 1e10;
4779
0
    } else if (ctm[i] < -1e10) {
4780
0
      ctm[i] = -1e10;
4781
0
    }
4782
0
  }
4783
0
}
4784
4785
void GfxState::concatCTM(double a, double b, double c,
4786
0
       double d, double e, double f) {
4787
0
  double a1 = ctm[0];
4788
0
  double b1 = ctm[1];
4789
0
  double c1 = ctm[2];
4790
0
  double d1 = ctm[3];
4791
0
  int i;
4792
4793
0
  ctm[0] = a * a1 + b * c1;
4794
0
  ctm[1] = a * b1 + b * d1;
4795
0
  ctm[2] = c * a1 + d * c1;
4796
0
  ctm[3] = c * b1 + d * d1;
4797
0
  ctm[4] = e * a1 + f * c1 + ctm[4];
4798
0
  ctm[5] = e * b1 + f * d1 + ctm[5];
4799
4800
  // avoid FP exceptions on badly messed up PDF files
4801
0
  for (i = 0; i < 6; ++i) {
4802
0
    if (ctm[i] > 1e10) {
4803
0
      ctm[i] = 1e10;
4804
0
    } else if (ctm[i] < -1e10) {
4805
0
      ctm[i] = -1e10;
4806
0
    }
4807
0
  }
4808
0
}
4809
4810
0
void GfxState::shiftCTM(double tx, double ty) {
4811
0
  ctm[4] += tx;
4812
0
  ctm[5] += ty;
4813
0
  clipXMin += tx;
4814
0
  clipYMin += ty;
4815
0
  clipXMax += tx;
4816
0
  clipYMax += ty;
4817
0
}
4818
4819
0
void GfxState::setFillColorSpace(GfxColorSpace *colorSpace) {
4820
0
  if (fillColorSpace) {
4821
0
    delete fillColorSpace;
4822
0
  }
4823
0
  fillColorSpace = colorSpace;
4824
0
}
4825
4826
0
void GfxState::setStrokeColorSpace(GfxColorSpace *colorSpace) {
4827
0
  if (strokeColorSpace) {
4828
0
    delete strokeColorSpace;
4829
0
  }
4830
0
  strokeColorSpace = colorSpace;
4831
0
}
4832
4833
0
void GfxState::setFillPattern(GfxPattern *pattern) {
4834
0
  if (fillPattern) {
4835
0
    delete fillPattern;
4836
0
  }
4837
0
  fillPattern = pattern;
4838
0
}
4839
4840
0
void GfxState::setStrokePattern(GfxPattern *pattern) {
4841
0
  if (strokePattern) {
4842
0
    delete strokePattern;
4843
0
  }
4844
0
  strokePattern = pattern;
4845
0
}
4846
4847
0
void GfxState::setRenderingIntent(GfxRenderingIntent ri) {
4848
0
  if (!(localParams && localParams->getForceRenderingIntent())) {
4849
0
    renderingIntent = ri;
4850
0
  }
4851
0
}
4852
4853
0
void GfxState::setTransfer(Function **funcs) {
4854
0
  int i;
4855
4856
0
  for (i = 0; i < 4; ++i) {
4857
0
    if (transfer[i]) {
4858
0
      delete transfer[i];
4859
0
    }
4860
0
    transfer[i] = funcs[i];
4861
0
  }
4862
0
}
4863
4864
0
void GfxState::setLineDash(double *dash, int length, double start) {
4865
0
  if (lineDash)
4866
0
    gfree(lineDash);
4867
0
  lineDash = dash;
4868
0
  lineDashLength = length;
4869
0
  lineDashStart = start;
4870
0
}
4871
4872
0
void GfxState::clearPath() {
4873
0
  delete path;
4874
0
  path = new GfxPath();
4875
0
}
4876
4877
0
void GfxState::clip() {
4878
0
  double xMin, yMin, xMax, yMax, x, y;
4879
0
  GfxSubpath *subpath;
4880
0
  int i, j;
4881
4882
0
  xMin = xMax = yMin = yMax = 0; // make gcc happy
4883
0
  for (i = 0; i < path->getNumSubpaths(); ++i) {
4884
0
    subpath = path->getSubpath(i);
4885
0
    for (j = 0; j < subpath->getNumPoints(); ++j) {
4886
0
      transform(subpath->getX(j), subpath->getY(j), &x, &y);
4887
0
      if (i == 0 && j == 0) {
4888
0
  xMin = xMax = x;
4889
0
  yMin = yMax = y;
4890
0
      } else {
4891
0
  if (x < xMin) {
4892
0
    xMin = x;
4893
0
  } else if (x > xMax) {
4894
0
    xMax = x;
4895
0
  }
4896
0
  if (y < yMin) {
4897
0
    yMin = y;
4898
0
  } else if (y > yMax) {
4899
0
    yMax = y;
4900
0
  }
4901
0
      }
4902
0
    }
4903
0
  }
4904
0
  if (xMin > clipXMin) {
4905
0
    clipXMin = xMin;
4906
0
  }
4907
0
  if (yMin > clipYMin) {
4908
0
    clipYMin = yMin;
4909
0
  }
4910
0
  if (xMax < clipXMax) {
4911
0
    clipXMax = xMax;
4912
0
  }
4913
0
  if (yMax < clipYMax) {
4914
0
    clipYMax = yMax;
4915
0
  }
4916
0
}
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
0
void GfxState::clipToRect(double xMin, double yMin, double xMax, double yMax) {
5066
0
  double x, y, xMin1, yMin1, xMax1, yMax1;
5067
5068
0
  transform(xMin, yMin, &x, &y);
5069
0
  xMin1 = xMax1 = x;
5070
0
  yMin1 = yMax1 = y;
5071
0
  transform(xMax, yMin, &x, &y);
5072
0
  if (x < xMin1) {
5073
0
    xMin1 = x;
5074
0
  } else if (x > xMax1) {
5075
0
    xMax1 = x;
5076
0
  }
5077
0
  if (y < yMin1) {
5078
0
    yMin1 = y;
5079
0
  } else if (y > yMax1) {
5080
0
    yMax1 = y;
5081
0
  }
5082
0
  transform(xMax, yMax, &x, &y);
5083
0
  if (x < xMin1) {
5084
0
    xMin1 = x;
5085
0
  } else if (x > xMax1) {
5086
0
    xMax1 = x;
5087
0
  }
5088
0
  if (y < yMin1) {
5089
0
    yMin1 = y;
5090
0
  } else if (y > yMax1) {
5091
0
    yMax1 = y;
5092
0
  }
5093
0
  transform(xMin, yMax, &x, &y);
5094
0
  if (x < xMin1) {
5095
0
    xMin1 = x;
5096
0
  } else if (x > xMax1) {
5097
0
    xMax1 = x;
5098
0
  }
5099
0
  if (y < yMin1) {
5100
0
    yMin1 = y;
5101
0
  } else if (y > yMax1) {
5102
0
    yMax1 = y;
5103
0
  }
5104
5105
0
  if (xMin1 > clipXMin) {
5106
0
    clipXMin = xMin1;
5107
0
  }
5108
0
  if (yMin1 > clipYMin) {
5109
0
    clipYMin = yMin1;
5110
0
  }
5111
0
  if (xMax1 < clipXMax) {
5112
0
    clipXMax = xMax1;
5113
0
  }
5114
0
  if (yMax1 < clipYMax) {
5115
0
    clipYMax = yMax1;
5116
0
  }
5117
0
}
5118
5119
0
void GfxState::textShift(double tx, double ty) {
5120
0
  double dx, dy;
5121
5122
0
  textTransformDelta(tx, ty, &dx, &dy);
5123
0
  curX += dx;
5124
0
  curY += dy;
5125
0
}
5126
5127
0
void GfxState::shift(double dx, double dy) {
5128
0
  curX += dx;
5129
0
  curY += dy;
5130
0
}
5131
5132
0
GfxState *GfxState::save() {
5133
0
  GfxState *newState;
5134
5135
0
  newState = copy();
5136
0
  newState->saved = this;
5137
0
  return newState;
5138
0
}
5139
5140
0
GfxState *GfxState::restore() {
5141
0
  GfxState *oldState;
5142
5143
0
  if (saved) {
5144
0
    oldState = saved;
5145
5146
    // these attributes aren't saved/restored by the q/Q operators
5147
0
    oldState->path = path;
5148
0
    oldState->curX = curX;
5149
0
    oldState->curY = curY;
5150
0
    oldState->lineX = lineX;
5151
0
    oldState->lineY = lineY;
5152
5153
0
    path = NULL;
5154
0
    saved = NULL;
5155
0
    delete this;
5156
5157
0
  } else {
5158
0
    oldState = this;
5159
0
  }
5160
5161
0
  return oldState;
5162
0
}
5163
5164
0
GBool GfxState::parseBlendMode(Object *obj, GfxBlendMode *mode) {
5165
0
  Object obj2;
5166
0
  int i, j;
5167
5168
0
  if (obj->isName()) {
5169
0
    for (i = 0; i < nGfxBlendModeNames; ++i) {
5170
0
      if (!strcmp(obj->getName(), gfxBlendModeNames[i].name)) {
5171
0
  *mode = gfxBlendModeNames[i].mode;
5172
0
  return gTrue;
5173
0
      }
5174
0
    }
5175
0
    return gFalse;
5176
0
  } 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
0
  } else {
5195
0
    return gFalse;
5196
0
  }
5197
0
}