~valavanisalex/ubuntu/utopic/inkscape/fix-1358863

« back to all changes in this revision

Viewing changes to .pc/0007-Poppler-0.26-compatibility.patch/src/extension/internal/pdfinput/pdf-parser.cpp

  • Committer: Package Import Robot
  • Author(s): Iain Lane
  • Date: 2014-06-20 17:42:08 UTC
  • mfrom: (2.5.12 sid)
  • Revision ID: package-import@ubuntu.com-20140620174208-3kdurxwjitvjrjph
Tags: 0.48.4-5ubuntu1
* Merge with Debian unstable. Remaining changes:
  - debian/control:
    + Set Ubuntu Developer as maintainer,
    + build-depend on dh-translation to handle Ubuntu translation,
    + demote pstoedit from Recommends to Suggests (because it's on universe),
  - debian/patches/0006_add_unity_quicklist_support.patch: add.
  - debian/patches/series: update.
  - debian/rules:
    + add dh_translation to handle Ubuntu translation,
    + add python2 to dh addon.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
 
2
 
 /** \file
3
 
 * PDF parsing using libpoppler
4
 
 *
5
 
 * Derived from poppler's Gfx.cc
6
 
 *
7
 
 * Copyright 1996-2003 Glyph & Cog, LLC
8
 
 *
9
 
 */
10
 
 
11
 
#ifdef HAVE_CONFIG_H
12
 
# include <config.h>
13
 
#endif
14
 
 
15
 
#ifdef HAVE_POPPLER
16
 
 
17
 
#ifdef USE_GCC_PRAGMAS
18
 
#pragma implementation
19
 
#endif
20
 
 
21
 
extern "C" {
22
 
        
23
 
#include <stdlib.h>
24
 
#include <stdio.h>
25
 
#include <stddef.h>
26
 
#include <string.h>
27
 
#include <math.h>
28
 
 
29
 
}
30
 
 
31
 
#include "svg-builder.h"
32
 
#include "Gfx.h"
33
 
#include "pdf-parser.h"
34
 
#include "unit-constants.h"
35
 
 
36
 
#include "goo/gmem.h"
37
 
#include "goo/GooTimer.h"
38
 
#include "goo/GooHash.h"
39
 
#include "GlobalParams.h"
40
 
#include "CharTypes.h"
41
 
#include "Object.h"
42
 
#include "Array.h"
43
 
#include "Dict.h"
44
 
#include "Stream.h"
45
 
#include "Lexer.h"
46
 
#include "Parser.h"
47
 
#include "GfxFont.h"
48
 
#include "GfxState.h"
49
 
#include "OutputDev.h"
50
 
#include "Page.h"
51
 
#include "Annot.h"
52
 
#include "Error.h"
53
 
 
54
 
// the MSVC math.h doesn't define this
55
 
#ifndef M_PI
56
 
#define M_PI 3.14159265358979323846
57
 
#endif
58
 
 
59
 
//------------------------------------------------------------------------
60
 
// constants
61
 
//------------------------------------------------------------------------
62
 
 
63
 
// Default max delta allowed in any color component for a shading fill.
64
 
#define defaultShadingColorDelta (dblToCol( 1 / 2.0 ))
65
 
 
66
 
// Default max recursive depth for a shading fill.
67
 
#define defaultShadingMaxDepth 6
68
 
 
69
 
// Max number of operators kept in the history list.
70
 
#define maxOperatorHistoryDepth 16
71
 
 
72
 
//------------------------------------------------------------------------
73
 
// Operator table
74
 
//------------------------------------------------------------------------
75
 
 
76
 
#ifdef WIN32 // this works around a bug in the VC7 compiler
77
 
#  pragma optimize("",off)
78
 
#endif
79
 
 
80
 
PdfOperator PdfParser::opTab[] = {
81
 
  {"\"",  3, {tchkNum,    tchkNum,    tchkString},
82
 
          &PdfParser::opMoveSetShowText},
83
 
  {"'",   1, {tchkString},
84
 
          &PdfParser::opMoveShowText},
85
 
  {"B",   0, {tchkNone},
86
 
          &PdfParser::opFillStroke},
87
 
  {"B*",  0, {tchkNone},
88
 
          &PdfParser::opEOFillStroke},
89
 
  {"BDC", 2, {tchkName,   tchkProps},
90
 
          &PdfParser::opBeginMarkedContent},
91
 
  {"BI",  0, {tchkNone},
92
 
          &PdfParser::opBeginImage},
93
 
  {"BMC", 1, {tchkName},
94
 
          &PdfParser::opBeginMarkedContent},
95
 
  {"BT",  0, {tchkNone},
96
 
          &PdfParser::opBeginText},
97
 
  {"BX",  0, {tchkNone},
98
 
          &PdfParser::opBeginIgnoreUndef},
99
 
  {"CS",  1, {tchkName},
100
 
          &PdfParser::opSetStrokeColorSpace},
101
 
  {"DP",  2, {tchkName,   tchkProps},
102
 
          &PdfParser::opMarkPoint},
103
 
  {"Do",  1, {tchkName},
104
 
          &PdfParser::opXObject},
105
 
  {"EI",  0, {tchkNone},
106
 
          &PdfParser::opEndImage},
107
 
  {"EMC", 0, {tchkNone},
108
 
          &PdfParser::opEndMarkedContent},
109
 
  {"ET",  0, {tchkNone},
110
 
          &PdfParser::opEndText},
111
 
  {"EX",  0, {tchkNone},
112
 
          &PdfParser::opEndIgnoreUndef},
113
 
  {"F",   0, {tchkNone},
114
 
          &PdfParser::opFill},
115
 
  {"G",   1, {tchkNum},
116
 
          &PdfParser::opSetStrokeGray},
117
 
  {"ID",  0, {tchkNone},
118
 
          &PdfParser::opImageData},
119
 
  {"J",   1, {tchkInt},
120
 
          &PdfParser::opSetLineCap},
121
 
  {"K",   4, {tchkNum,    tchkNum,    tchkNum,    tchkNum},
122
 
          &PdfParser::opSetStrokeCMYKColor},
123
 
  {"M",   1, {tchkNum},
124
 
          &PdfParser::opSetMiterLimit},
125
 
  {"MP",  1, {tchkName},
126
 
          &PdfParser::opMarkPoint},
127
 
  {"Q",   0, {tchkNone},
128
 
          &PdfParser::opRestore},
129
 
  {"RG",  3, {tchkNum,    tchkNum,    tchkNum},
130
 
          &PdfParser::opSetStrokeRGBColor},
131
 
  {"S",   0, {tchkNone},
132
 
          &PdfParser::opStroke},
133
 
  {"SC",  -4, {tchkNum,   tchkNum,    tchkNum,    tchkNum},
134
 
          &PdfParser::opSetStrokeColor},
135
 
  {"SCN", -33, {tchkSCN,   tchkSCN,    tchkSCN,    tchkSCN,
136
 
                tchkSCN,   tchkSCN,    tchkSCN,    tchkSCN,
137
 
                tchkSCN,   tchkSCN,    tchkSCN,    tchkSCN,
138
 
                tchkSCN,   tchkSCN,    tchkSCN,    tchkSCN,
139
 
                tchkSCN,   tchkSCN,    tchkSCN,    tchkSCN,
140
 
                tchkSCN,   tchkSCN,    tchkSCN,    tchkSCN,
141
 
                tchkSCN,   tchkSCN,    tchkSCN,    tchkSCN,
142
 
                tchkSCN,   tchkSCN,    tchkSCN,    tchkSCN,
143
 
                tchkSCN},
144
 
          &PdfParser::opSetStrokeColorN},
145
 
  {"T*",  0, {tchkNone},
146
 
          &PdfParser::opTextNextLine},
147
 
  {"TD",  2, {tchkNum,    tchkNum},
148
 
          &PdfParser::opTextMoveSet},
149
 
  {"TJ",  1, {tchkArray},
150
 
          &PdfParser::opShowSpaceText},
151
 
  {"TL",  1, {tchkNum},
152
 
          &PdfParser::opSetTextLeading},
153
 
  {"Tc",  1, {tchkNum},
154
 
          &PdfParser::opSetCharSpacing},
155
 
  {"Td",  2, {tchkNum,    tchkNum},
156
 
          &PdfParser::opTextMove},
157
 
  {"Tf",  2, {tchkName,   tchkNum},
158
 
          &PdfParser::opSetFont},
159
 
  {"Tj",  1, {tchkString},
160
 
          &PdfParser::opShowText},
161
 
  {"Tm",  6, {tchkNum,    tchkNum,    tchkNum,    tchkNum,
162
 
              tchkNum,    tchkNum},
163
 
          &PdfParser::opSetTextMatrix},
164
 
  {"Tr",  1, {tchkInt},
165
 
          &PdfParser::opSetTextRender},
166
 
  {"Ts",  1, {tchkNum},
167
 
          &PdfParser::opSetTextRise},
168
 
  {"Tw",  1, {tchkNum},
169
 
          &PdfParser::opSetWordSpacing},
170
 
  {"Tz",  1, {tchkNum},
171
 
          &PdfParser::opSetHorizScaling},
172
 
  {"W",   0, {tchkNone},
173
 
          &PdfParser::opClip},
174
 
  {"W*",  0, {tchkNone},
175
 
          &PdfParser::opEOClip},
176
 
  {"b",   0, {tchkNone},
177
 
          &PdfParser::opCloseFillStroke},
178
 
  {"b*",  0, {tchkNone},
179
 
          &PdfParser::opCloseEOFillStroke},
180
 
  {"c",   6, {tchkNum,    tchkNum,    tchkNum,    tchkNum,
181
 
              tchkNum,    tchkNum},
182
 
          &PdfParser::opCurveTo},
183
 
  {"cm",  6, {tchkNum,    tchkNum,    tchkNum,    tchkNum,
184
 
              tchkNum,    tchkNum},
185
 
          &PdfParser::opConcat},
186
 
  {"cs",  1, {tchkName},
187
 
          &PdfParser::opSetFillColorSpace},
188
 
  {"d",   2, {tchkArray,  tchkNum},
189
 
          &PdfParser::opSetDash},
190
 
  {"d0",  2, {tchkNum,    tchkNum},
191
 
          &PdfParser::opSetCharWidth},
192
 
  {"d1",  6, {tchkNum,    tchkNum,    tchkNum,    tchkNum,
193
 
              tchkNum,    tchkNum},
194
 
          &PdfParser::opSetCacheDevice},
195
 
  {"f",   0, {tchkNone},
196
 
          &PdfParser::opFill},
197
 
  {"f*",  0, {tchkNone},
198
 
          &PdfParser::opEOFill},
199
 
  {"g",   1, {tchkNum},
200
 
          &PdfParser::opSetFillGray},
201
 
  {"gs",  1, {tchkName},
202
 
          &PdfParser::opSetExtGState},
203
 
  {"h",   0, {tchkNone},
204
 
          &PdfParser::opClosePath},
205
 
  {"i",   1, {tchkNum},
206
 
          &PdfParser::opSetFlat},
207
 
  {"j",   1, {tchkInt},
208
 
          &PdfParser::opSetLineJoin},
209
 
  {"k",   4, {tchkNum,    tchkNum,    tchkNum,    tchkNum},
210
 
          &PdfParser::opSetFillCMYKColor},
211
 
  {"l",   2, {tchkNum,    tchkNum},
212
 
          &PdfParser::opLineTo},
213
 
  {"m",   2, {tchkNum,    tchkNum},
214
 
          &PdfParser::opMoveTo},
215
 
  {"n",   0, {tchkNone},
216
 
          &PdfParser::opEndPath},
217
 
  {"q",   0, {tchkNone},
218
 
          &PdfParser::opSave},
219
 
  {"re",  4, {tchkNum,    tchkNum,    tchkNum,    tchkNum},
220
 
          &PdfParser::opRectangle},
221
 
  {"rg",  3, {tchkNum,    tchkNum,    tchkNum},
222
 
          &PdfParser::opSetFillRGBColor},
223
 
  {"ri",  1, {tchkName},
224
 
          &PdfParser::opSetRenderingIntent},
225
 
  {"s",   0, {tchkNone},
226
 
          &PdfParser::opCloseStroke},
227
 
  {"sc",  -4, {tchkNum,   tchkNum,    tchkNum,    tchkNum},
228
 
          &PdfParser::opSetFillColor},
229
 
  {"scn", -33, {tchkSCN,   tchkSCN,    tchkSCN,    tchkSCN,
230
 
                tchkSCN,   tchkSCN,    tchkSCN,    tchkSCN,
231
 
                tchkSCN,   tchkSCN,    tchkSCN,    tchkSCN,
232
 
                tchkSCN,   tchkSCN,    tchkSCN,    tchkSCN,
233
 
                tchkSCN,   tchkSCN,    tchkSCN,    tchkSCN,
234
 
                tchkSCN,   tchkSCN,    tchkSCN,    tchkSCN,
235
 
                tchkSCN,   tchkSCN,    tchkSCN,    tchkSCN,
236
 
                tchkSCN,   tchkSCN,    tchkSCN,    tchkSCN,
237
 
                tchkSCN},
238
 
          &PdfParser::opSetFillColorN},
239
 
  {"sh",  1, {tchkName},
240
 
          &PdfParser::opShFill},
241
 
  {"v",   4, {tchkNum,    tchkNum,    tchkNum,    tchkNum},
242
 
          &PdfParser::opCurveTo1},
243
 
  {"w",   1, {tchkNum},
244
 
          &PdfParser::opSetLineWidth},
245
 
  {"y",   4, {tchkNum,    tchkNum,    tchkNum,    tchkNum},
246
 
          &PdfParser::opCurveTo2}
247
 
};
248
 
 
249
 
#ifdef WIN32 // this works around a bug in the VC7 compiler
250
 
#  pragma optimize("",on)
251
 
#endif
252
 
 
253
 
#define numOps (sizeof(opTab) / sizeof(PdfOperator))
254
 
 
255
 
//------------------------------------------------------------------------
256
 
// PdfParser
257
 
//------------------------------------------------------------------------
258
 
 
259
 
PdfParser::PdfParser(XRef *xrefA, Inkscape::Extension::Internal::SvgBuilder *builderA,
260
 
                     int pageNum, int rotate, Dict *resDict,
261
 
                     PDFRectangle *box, PDFRectangle *cropBox) {
262
 
 
263
 
  int i;
264
 
 
265
 
  xref = xrefA;
266
 
  subPage = gFalse;
267
 
  printCommands = false;
268
 
 
269
 
  // start the resource stack
270
 
  res = new GfxResources(xref, resDict, NULL);
271
 
 
272
 
  // initialize
273
 
  state = new GfxState(72.0, 72.0, box, rotate, gTrue);
274
 
  clipHistory = new ClipHistoryEntry();
275
 
  setDefaultApproximationPrecision();
276
 
  fontChanged = gFalse;
277
 
  clip = clipNone;
278
 
  ignoreUndef = 0;
279
 
  operatorHistory = NULL;
280
 
  builder = builderA;
281
 
  builder->setDocumentSize(state->getPageWidth()*PX_PER_PT,
282
 
                           state->getPageHeight()*PX_PER_PT);
283
 
 
284
 
  double *ctm = state->getCTM();
285
 
  double scaledCTM[6];
286
 
  for (i = 0; i < 6; ++i) {
287
 
    baseMatrix[i] = ctm[i];
288
 
    scaledCTM[i] = PX_PER_PT * ctm[i];
289
 
  }
290
 
  saveState();
291
 
  builder->setTransform((double*)&scaledCTM);
292
 
  formDepth = 0;
293
 
 
294
 
  // set crop box
295
 
  if (cropBox) {
296
 
    if (printCommands)
297
 
        printf("cropBox: %f %f %f %f\n", cropBox->x1, cropBox->y1, cropBox->x2, cropBox->y2);
298
 
    // do not clip if it's not needed
299
 
    if (cropBox->x1 != 0.0 || cropBox->y1 != 0.0 ||
300
 
        cropBox->x2 != state->getPageWidth() || cropBox->y2 != state->getPageHeight()) {
301
 
        
302
 
        state->moveTo(cropBox->x1, cropBox->y1);
303
 
        state->lineTo(cropBox->x2, cropBox->y1);
304
 
        state->lineTo(cropBox->x2, cropBox->y2);
305
 
        state->lineTo(cropBox->x1, cropBox->y2);
306
 
        state->closePath();
307
 
        state->clip();
308
 
        clipHistory->setClip(state->getPath(), clipNormal);
309
 
        builder->setClipPath(state);
310
 
        state->clearPath();
311
 
    }
312
 
  }
313
 
  pushOperator("startPage");
314
 
}
315
 
 
316
 
PdfParser::PdfParser(XRef *xrefA, Inkscape::Extension::Internal::SvgBuilder *builderA,
317
 
                     Dict *resDict, PDFRectangle *box) {
318
 
 
319
 
  int i;
320
 
 
321
 
  xref = xrefA;
322
 
  subPage = gTrue;
323
 
  printCommands = false;
324
 
 
325
 
  // start the resource stack
326
 
  res = new GfxResources(xref, resDict, NULL);
327
 
 
328
 
  // initialize
329
 
  operatorHistory = NULL;
330
 
  builder = builderA;
331
 
  state = new GfxState(72, 72, box, 0, gFalse);
332
 
  clipHistory = new ClipHistoryEntry();
333
 
  setDefaultApproximationPrecision();
334
 
  
335
 
  fontChanged = gFalse;
336
 
  clip = clipNone;
337
 
  ignoreUndef = 0;
338
 
  for (i = 0; i < 6; ++i) {
339
 
    baseMatrix[i] = state->getCTM()[i];
340
 
  }
341
 
  formDepth = 0;
342
 
}
343
 
 
344
 
PdfParser::~PdfParser() {
345
 
  while (state->hasSaves()) {
346
 
    restoreState();
347
 
  }
348
 
  if (!subPage) {
349
 
    //out->endPage();
350
 
  }
351
 
  while (res) {
352
 
    popResources();
353
 
  }
354
 
  if (state) {
355
 
    delete state;
356
 
  }
357
 
  if (clipHistory) {
358
 
    delete clipHistory;
359
 
  }
360
 
}
361
 
 
362
 
void PdfParser::parse(Object *obj, GBool topLevel) {
363
 
  Object obj2;
364
 
  int i;
365
 
 
366
 
  if (obj->isArray()) {
367
 
    for (i = 0; i < obj->arrayGetLength(); ++i) {
368
 
      obj->arrayGet(i, &obj2);
369
 
      if (!obj2.isStream()) {
370
 
#ifdef POPPLER_NEW_ERRORAPI
371
 
        error(errInternal, -1, "Weird page contents");
372
 
#else
373
 
        error(-1, const_cast<char*>("Weird page contents"));
374
 
#endif
375
 
        obj2.free();
376
 
        return;
377
 
      }
378
 
      obj2.free();
379
 
    }
380
 
  } else if (!obj->isStream()) {
381
 
#ifdef POPPLER_NEW_ERRORAPI
382
 
        error(errInternal, -1, "Weird page contents");
383
 
#else
384
 
        error(-1, const_cast<char*>("Weird page contents"));
385
 
#endif
386
 
        return;
387
 
  }
388
 
  parser = new Parser(xref, new Lexer(xref, obj), gFalse);
389
 
  go(topLevel);
390
 
  delete parser;
391
 
  parser = NULL;
392
 
}
393
 
 
394
 
void PdfParser::go(GBool topLevel) {
395
 
  Object obj;
396
 
  Object args[maxArgs];
397
 
  int numArgs, i;
398
 
 
399
 
  // scan a sequence of objects
400
 
  numArgs = 0;
401
 
  parser->getObj(&obj);
402
 
  while (!obj.isEOF()) {
403
 
 
404
 
    // got a command - execute it
405
 
    if (obj.isCmd()) {
406
 
      if (printCommands) {
407
 
        obj.print(stdout);
408
 
        for (i = 0; i < numArgs; ++i) {
409
 
          printf(" ");
410
 
          args[i].print(stdout);
411
 
        }
412
 
        printf("\n");
413
 
        fflush(stdout);
414
 
      }
415
 
 
416
 
      // Run the operation
417
 
      execOp(&obj, args, numArgs);
418
 
 
419
 
      obj.free();
420
 
      for (i = 0; i < numArgs; ++i)
421
 
        args[i].free();
422
 
      numArgs = 0;
423
 
 
424
 
    // got an argument - save it
425
 
    } else if (numArgs < maxArgs) {
426
 
      args[numArgs++] = obj;
427
 
 
428
 
    // too many arguments - something is wrong
429
 
    } else {
430
 
#ifdef POPPLER_NEW_ERRORAPI
431
 
      error(errSyntaxError, getPos(), "Too many args in content stream");
432
 
#else
433
 
      error(getPos(), const_cast<char*>("Too many args in content stream"));
434
 
#endif
435
 
      if (printCommands) {
436
 
        printf("throwing away arg: ");
437
 
        obj.print(stdout);
438
 
        printf("\n");
439
 
        fflush(stdout);
440
 
      }
441
 
      obj.free();
442
 
    }
443
 
 
444
 
    // grab the next object
445
 
    parser->getObj(&obj);
446
 
  }
447
 
  obj.free();
448
 
 
449
 
  // args at end with no command
450
 
  if (numArgs > 0) {
451
 
#ifdef POPPLER_NEW_ERRORAPI
452
 
    error(errSyntaxError, getPos(), "Leftover args in content stream");
453
 
#else
454
 
    error(getPos(), const_cast<char*>("Leftover args in content stream"));
455
 
#endif
456
 
    if (printCommands) {
457
 
      printf("%d leftovers:", numArgs);
458
 
      for (i = 0; i < numArgs; ++i) {
459
 
        printf(" ");
460
 
        args[i].print(stdout);
461
 
      }
462
 
      printf("\n");
463
 
      fflush(stdout);
464
 
    }
465
 
    for (i = 0; i < numArgs; ++i)
466
 
      args[i].free();
467
 
  }
468
 
}
469
 
 
470
 
void PdfParser::pushOperator(const char *name) {
471
 
    OpHistoryEntry *newEntry = new OpHistoryEntry;
472
 
    newEntry->name = name;
473
 
    newEntry->state = NULL;
474
 
    newEntry->depth = (operatorHistory != NULL ? (operatorHistory->depth+1) : 0);
475
 
    newEntry->next = operatorHistory;
476
 
    operatorHistory = newEntry;
477
 
 
478
 
    // Truncate list if needed
479
 
    if (operatorHistory->depth > maxOperatorHistoryDepth) {
480
 
        OpHistoryEntry *curr = operatorHistory;
481
 
        OpHistoryEntry *prev = NULL;
482
 
        while (curr && curr->next != NULL) {
483
 
            curr->depth--;
484
 
            prev = curr;
485
 
            curr = curr->next;
486
 
        }
487
 
        if (prev) {
488
 
            if (curr->state != NULL)
489
 
                delete curr->state;
490
 
            delete curr;
491
 
            prev->next = NULL;
492
 
        }
493
 
    }
494
 
}
495
 
 
496
 
const char *PdfParser::getPreviousOperator(unsigned int look_back) {
497
 
    OpHistoryEntry *prev = NULL;
498
 
    if (operatorHistory != NULL && look_back > 0) {
499
 
        prev = operatorHistory->next;
500
 
        while (--look_back > 0 && prev != NULL) {
501
 
            prev = prev->next;
502
 
        }
503
 
    }
504
 
    if (prev != NULL) {
505
 
        return prev->name;
506
 
    } else {
507
 
        return "";
508
 
    }
509
 
}
510
 
 
511
 
void PdfParser::execOp(Object *cmd, Object args[], int numArgs) {
512
 
  PdfOperator *op;
513
 
  char *name;
514
 
  Object *argPtr;
515
 
  int i;
516
 
 
517
 
  // find operator
518
 
  name = cmd->getCmd();
519
 
  if (!(op = findOp(name))) {
520
 
    if (ignoreUndef == 0)
521
 
#ifdef POPPLER_NEW_ERRORAPI
522
 
      error(errSyntaxError, getPos(), "Unknown operator '{0:s}'", name);
523
 
#else
524
 
      error(getPos(), const_cast<char*>("Unknown operator '%s'"), name);
525
 
#endif
526
 
    return;
527
 
  }
528
 
 
529
 
  // type check args
530
 
  argPtr = args;
531
 
  if (op->numArgs >= 0) {
532
 
    if (numArgs < op->numArgs) {
533
 
#ifdef POPPLER_NEW_ERRORAPI
534
 
      error(errSyntaxError, getPos(), "Too few ({0:d}) args to '{1:d}' operator", numArgs, name);
535
 
#else
536
 
      error(getPos(), const_cast<char*>("Too few (%d) args to '%s' operator"), numArgs, name);
537
 
#endif
538
 
      return;
539
 
    }
540
 
    if (numArgs > op->numArgs) {
541
 
#if 0
542
 
#ifdef POPPLER_NEW_ERRORAPI
543
 
      error(errSyntaxError, getPos(), "Too many ({0:d}) args to '{1:s}' operator", numArgs, name);
544
 
#else
545
 
      error(getPos(), "Too many (%d) args to '%s' operator", numArgs, name);
546
 
#endif
547
 
#endif
548
 
      argPtr += numArgs - op->numArgs;
549
 
      numArgs = op->numArgs;
550
 
    }
551
 
  } else {
552
 
    if (numArgs > -op->numArgs) {
553
 
#ifdef POPPLER_NEW_ERRORAPI
554
 
      error(errSyntaxError, getPos(), "Too many ({0:d}) args to '{1:s}' operator",
555
 
#else
556
 
      error(getPos(), const_cast<char*>("Too many (%d) args to '%s' operator"),
557
 
#endif
558
 
            numArgs, name);
559
 
      return;
560
 
    }
561
 
  }
562
 
  for (i = 0; i < numArgs; ++i) {
563
 
    if (!checkArg(&argPtr[i], op->tchk[i])) {
564
 
#ifdef POPPLER_NEW_ERRORAPI
565
 
      error(errSyntaxError, getPos(), "Arg #{0:d} to '{1:s}' operator is wrong type ({2:s})",
566
 
#else
567
 
      error(getPos(), const_cast<char*>("Arg #%d to '%s' operator is wrong type (%s)"),
568
 
#endif
569
 
            i, name, argPtr[i].getTypeName());
570
 
      return;
571
 
    }
572
 
  }
573
 
 
574
 
  // add to history
575
 
  pushOperator((char*)&op->name);
576
 
 
577
 
  // do it
578
 
  (this->*op->func)(argPtr, numArgs);
579
 
}
580
 
 
581
 
PdfOperator *PdfParser::findOp(char *name) {
582
 
  int a, b, m, cmp;
583
 
 
584
 
  a = -1;
585
 
  b = numOps;
586
 
  // invariant: opTab[a] < name < opTab[b]
587
 
  while (b - a > 1) {
588
 
    m = (a + b) / 2;
589
 
    cmp = strcmp(opTab[m].name, name);
590
 
    if (cmp < 0)
591
 
      a = m;
592
 
    else if (cmp > 0)
593
 
      b = m;
594
 
    else
595
 
      a = b = m;
596
 
  }
597
 
  if (cmp != 0)
598
 
    return NULL;
599
 
  return &opTab[a];
600
 
}
601
 
 
602
 
GBool PdfParser::checkArg(Object *arg, TchkType type) {
603
 
  switch (type) {
604
 
  case tchkBool:   return arg->isBool();
605
 
  case tchkInt:    return arg->isInt();
606
 
  case tchkNum:    return arg->isNum();
607
 
  case tchkString: return arg->isString();
608
 
  case tchkName:   return arg->isName();
609
 
  case tchkArray:  return arg->isArray();
610
 
  case tchkProps:  return arg->isDict() || arg->isName();
611
 
  case tchkSCN:    return arg->isNum() || arg->isName();
612
 
  case tchkNone:   return gFalse;
613
 
  }
614
 
  return gFalse;
615
 
}
616
 
 
617
 
int PdfParser::getPos() {
618
 
  return parser ? parser->getPos() : -1;
619
 
}
620
 
 
621
 
//------------------------------------------------------------------------
622
 
// graphics state operators
623
 
//------------------------------------------------------------------------
624
 
 
625
 
void PdfParser::opSave(Object args[], int numArgs) {
626
 
  saveState();
627
 
}
628
 
 
629
 
void PdfParser::opRestore(Object args[], int numArgs) {
630
 
  restoreState();
631
 
}
632
 
 
633
 
void PdfParser::opConcat(Object args[], int numArgs) {
634
 
  state->concatCTM(args[0].getNum(), args[1].getNum(),
635
 
                   args[2].getNum(), args[3].getNum(),
636
 
                   args[4].getNum(), args[5].getNum());
637
 
  const char *prevOp = getPreviousOperator();
638
 
  double a0 = args[0].getNum();
639
 
  double a1 = args[1].getNum();
640
 
  double a2 = args[2].getNum();
641
 
  double a3 = args[3].getNum();
642
 
  double a4 = args[4].getNum();
643
 
  double a5 = args[5].getNum();
644
 
  if (!strcmp(prevOp, "q")) {
645
 
      builder->setTransform(a0, a1, a2, a3, a4, a5);
646
 
  } else if (!strcmp(prevOp, "cm") || !strcmp(prevOp, "startPage")) {
647
 
      // multiply it with the previous transform
648
 
      double otherMatrix[6];
649
 
      if (!builder->getTransform(otherMatrix)) { // invalid transform
650
 
          // construct identity matrix
651
 
          otherMatrix[0] = otherMatrix[3] = 1.0;
652
 
          otherMatrix[1] = otherMatrix[2] = otherMatrix[4] = otherMatrix[5] = 0.0;
653
 
      }
654
 
      double c0 = a0*otherMatrix[0] + a1*otherMatrix[2];
655
 
      double c1 = a0*otherMatrix[1] + a1*otherMatrix[3];
656
 
      double c2 = a2*otherMatrix[0] + a3*otherMatrix[2];
657
 
      double c3 = a2*otherMatrix[1] + a3*otherMatrix[3];
658
 
      double c4 = a4*otherMatrix[0] + a5*otherMatrix[2] + otherMatrix[4];
659
 
      double c5 = a4*otherMatrix[1] + a5*otherMatrix[3] + otherMatrix[5];
660
 
      builder->setTransform(c0, c1, c2, c3, c4, c5);
661
 
  } else {
662
 
      builder->pushGroup();
663
 
      builder->setTransform(a0, a1, a2, a3, a4, a5);
664
 
  }
665
 
  fontChanged = gTrue;
666
 
}
667
 
 
668
 
void PdfParser::opSetDash(Object args[], int numArgs) {
669
 
  Array *a;
670
 
  int length;
671
 
  Object obj;
672
 
  double *dash;
673
 
  int i;
674
 
 
675
 
  a = args[0].getArray();
676
 
  length = a->getLength();
677
 
  if (length == 0) {
678
 
    dash = NULL;
679
 
  } else {
680
 
    dash = (double *)gmallocn(length, sizeof(double));
681
 
    for (i = 0; i < length; ++i) {
682
 
      dash[i] = a->get(i, &obj)->getNum();
683
 
      obj.free();
684
 
    }
685
 
  }
686
 
  state->setLineDash(dash, length, args[1].getNum());
687
 
  builder->updateStyle(state);
688
 
}
689
 
 
690
 
void PdfParser::opSetFlat(Object args[], int numArgs) {
691
 
  state->setFlatness((int)args[0].getNum());
692
 
}
693
 
 
694
 
void PdfParser::opSetLineJoin(Object args[], int numArgs) {
695
 
  state->setLineJoin(args[0].getInt());
696
 
  builder->updateStyle(state);
697
 
}
698
 
 
699
 
void PdfParser::opSetLineCap(Object args[], int numArgs) {
700
 
  state->setLineCap(args[0].getInt());
701
 
  builder->updateStyle(state);
702
 
}
703
 
 
704
 
void PdfParser::opSetMiterLimit(Object args[], int numArgs) {
705
 
  state->setMiterLimit(args[0].getNum());
706
 
  builder->updateStyle(state);
707
 
}
708
 
 
709
 
void PdfParser::opSetLineWidth(Object args[], int numArgs) {
710
 
  state->setLineWidth(args[0].getNum());
711
 
  builder->updateStyle(state);
712
 
}
713
 
 
714
 
void PdfParser::opSetExtGState(Object args[], int numArgs) {
715
 
  Object obj1, obj2, obj3, obj4, obj5;
716
 
  GfxBlendMode mode;
717
 
  GBool haveFillOP;
718
 
  Function *funcs[4];
719
 
  GfxColor backdropColor;
720
 
  GBool haveBackdropColor;
721
 
  GfxColorSpace *blendingColorSpace;
722
 
  GBool alpha, isolated, knockout;
723
 
  int i;
724
 
 
725
 
  if (!res->lookupGState(args[0].getName(), &obj1)) {
726
 
    return;
727
 
  }
728
 
  if (!obj1.isDict()) {
729
 
#ifdef POPPLER_NEW_ERRORAPI
730
 
    error(errSyntaxError, getPos(), "ExtGState '{0:s}' is wrong type"), args[0].getName();
731
 
#else
732
 
    error(getPos(), const_cast<char*>("ExtGState '%s' is wrong type"), args[0].getName());
733
 
#endif
734
 
    obj1.free();
735
 
    return;
736
 
  }
737
 
  if (printCommands) {
738
 
    printf("  gfx state dict: ");
739
 
    obj1.print();
740
 
    printf("\n");
741
 
  }
742
 
 
743
 
  // transparency support: blend mode, fill/stroke opacity
744
 
  if (!obj1.dictLookup(const_cast<char*>("BM"), &obj2)->isNull()) {
745
 
    if (state->parseBlendMode(&obj2, &mode)) {
746
 
      state->setBlendMode(mode);
747
 
    } else {
748
 
#ifdef POPPLER_NEW_ERRORAPI
749
 
      error(errSyntaxError, getPos(), "Invalid blend mode in ExtGState");
750
 
#else
751
 
      error(getPos(), const_cast<char*>("Invalid blend mode in ExtGState"));
752
 
#endif
753
 
    }
754
 
  }
755
 
  obj2.free();
756
 
  if (obj1.dictLookup(const_cast<char*>("ca"), &obj2)->isNum()) {
757
 
    state->setFillOpacity(obj2.getNum());
758
 
  }
759
 
  obj2.free();
760
 
  if (obj1.dictLookup(const_cast<char*>("CA"), &obj2)->isNum()) {
761
 
    state->setStrokeOpacity(obj2.getNum());
762
 
  }
763
 
  obj2.free();
764
 
 
765
 
  // fill/stroke overprint
766
 
  if ((haveFillOP = (obj1.dictLookup(const_cast<char*>("op"), &obj2)->isBool()))) {
767
 
    state->setFillOverprint(obj2.getBool());
768
 
  }
769
 
  obj2.free();
770
 
  if (obj1.dictLookup(const_cast<char*>("OP"), &obj2)->isBool()) {
771
 
    state->setStrokeOverprint(obj2.getBool());
772
 
    if (!haveFillOP) {
773
 
      state->setFillOverprint(obj2.getBool());
774
 
    }
775
 
  }
776
 
  obj2.free();
777
 
 
778
 
  // stroke adjust
779
 
  if (obj1.dictLookup(const_cast<char*>("SA"), &obj2)->isBool()) {
780
 
    state->setStrokeAdjust(obj2.getBool());
781
 
  }
782
 
  obj2.free();
783
 
 
784
 
  // transfer function
785
 
  if (obj1.dictLookup(const_cast<char*>("TR2"), &obj2)->isNull()) {
786
 
    obj2.free();
787
 
    obj1.dictLookup(const_cast<char*>("TR"), &obj2);
788
 
  }
789
 
  if (obj2.isName(const_cast<char*>("Default")) ||
790
 
      obj2.isName(const_cast<char*>("Identity"))) {
791
 
    funcs[0] = funcs[1] = funcs[2] = funcs[3] = NULL;
792
 
    state->setTransfer(funcs);
793
 
  } else if (obj2.isArray() && obj2.arrayGetLength() == 4) {
794
 
    for (i = 0; i < 4; ++i) {
795
 
      obj2.arrayGet(i, &obj3);
796
 
      funcs[i] = Function::parse(&obj3);
797
 
      obj3.free();
798
 
      if (!funcs[i]) {
799
 
        break;
800
 
      }
801
 
    }
802
 
    if (i == 4) {
803
 
      state->setTransfer(funcs);
804
 
    }
805
 
  } else if (obj2.isName() || obj2.isDict() || obj2.isStream()) {
806
 
    if ((funcs[0] = Function::parse(&obj2))) {
807
 
      funcs[1] = funcs[2] = funcs[3] = NULL;
808
 
      state->setTransfer(funcs);
809
 
    }
810
 
  } else if (!obj2.isNull()) {
811
 
#ifdef POPPLER_NEW_ERRORAPI
812
 
    error(errSyntaxError, getPos(), "Invalid transfer function in ExtGState");
813
 
#else
814
 
    error(getPos(), const_cast<char*>("Invalid transfer function in ExtGState"));
815
 
#endif
816
 
  }
817
 
  obj2.free();
818
 
 
819
 
  // soft mask
820
 
  if (!obj1.dictLookup(const_cast<char*>("SMask"), &obj2)->isNull()) {
821
 
    if (obj2.isName(const_cast<char*>("None"))) {
822
 
      builder->clearSoftMask(state);
823
 
    } else if (obj2.isDict()) {
824
 
      if (obj2.dictLookup(const_cast<char*>("S"), &obj3)->isName(const_cast<char*>("Alpha"))) {
825
 
        alpha = gTrue;
826
 
      } else { // "Luminosity"
827
 
        alpha = gFalse;
828
 
      }
829
 
      obj3.free();
830
 
      funcs[0] = NULL;
831
 
      if (!obj2.dictLookup(const_cast<char*>("TR"), &obj3)->isNull()) {
832
 
        funcs[0] = Function::parse(&obj3);
833
 
        if (funcs[0]->getInputSize() != 1 ||
834
 
            funcs[0]->getOutputSize() != 1) {
835
 
#ifdef POPPLER_NEW_ERRORAPI
836
 
          error(errSyntaxError, getPos(), "Invalid transfer function in soft mask in ExtGState");
837
 
#else
838
 
          error(getPos(), const_cast<char*>("Invalid transfer function in soft mask in ExtGState"));
839
 
#endif
840
 
          delete funcs[0];
841
 
          funcs[0] = NULL;
842
 
        }
843
 
      }
844
 
      obj3.free();
845
 
      if ((haveBackdropColor = obj2.dictLookup(const_cast<char*>("BC"), &obj3)->isArray())) {
846
 
        for (i = 0; i < gfxColorMaxComps; ++i) {
847
 
          backdropColor.c[i] = 0;
848
 
        }
849
 
        for (i = 0; i < obj3.arrayGetLength() && i < gfxColorMaxComps; ++i) {
850
 
          obj3.arrayGet(i, &obj4);
851
 
          if (obj4.isNum()) {
852
 
            backdropColor.c[i] = dblToCol(obj4.getNum());
853
 
          }
854
 
          obj4.free();
855
 
        }
856
 
      }
857
 
      obj3.free();
858
 
      if (obj2.dictLookup(const_cast<char*>("G"), &obj3)->isStream()) {
859
 
        if (obj3.streamGetDict()->lookup(const_cast<char*>("Group"), &obj4)->isDict()) {
860
 
          blendingColorSpace = NULL;
861
 
          isolated = knockout = gFalse;
862
 
          if (!obj4.dictLookup(const_cast<char*>("CS"), &obj5)->isNull()) {
863
 
#if defined(POPPLER_NEW_COLOR_SPACE_API) || defined(POPPLER_NEW_ERRORAPI)
864
 
            blendingColorSpace = GfxColorSpace::parse(&obj5, NULL);
865
 
#else
866
 
            blendingColorSpace = GfxColorSpace::parse(&obj5);
867
 
#endif
868
 
          }
869
 
          obj5.free();
870
 
          if (obj4.dictLookup(const_cast<char*>("I"), &obj5)->isBool()) {
871
 
            isolated = obj5.getBool();
872
 
          }
873
 
          obj5.free();
874
 
          if (obj4.dictLookup(const_cast<char*>("K"), &obj5)->isBool()) {
875
 
            knockout = obj5.getBool();
876
 
          }
877
 
          obj5.free();
878
 
          if (!haveBackdropColor) {
879
 
            if (blendingColorSpace) {
880
 
              blendingColorSpace->getDefaultColor(&backdropColor);
881
 
            } else {
882
 
              //~ need to get the parent or default color space (?)
883
 
              for (i = 0; i < gfxColorMaxComps; ++i) {
884
 
                backdropColor.c[i] = 0;
885
 
              }
886
 
            }
887
 
          }
888
 
          doSoftMask(&obj3, alpha, blendingColorSpace,
889
 
                     isolated, knockout, funcs[0], &backdropColor);
890
 
          if (funcs[0]) {
891
 
            delete funcs[0];
892
 
          }
893
 
        } else {
894
 
#ifdef POPPLER_NEW_ERRORAPI
895
 
          error(errSyntaxError, getPos(), "Invalid soft mask in ExtGState - missing group");
896
 
#else
897
 
          error(getPos(), const_cast<char*>("Invalid soft mask in ExtGState - missing group"));
898
 
#endif
899
 
        }
900
 
        obj4.free();
901
 
      } else {
902
 
#ifdef POPPLER_NEW_ERRORAPI
903
 
        error(errSyntaxError, getPos(), "Invalid soft mask in ExtGState - missing group");
904
 
#else
905
 
        error(getPos(), const_cast<char*>("Invalid soft mask in ExtGState - missing group"));
906
 
#endif
907
 
      }
908
 
      obj3.free();
909
 
    } else if (!obj2.isNull()) {
910
 
#ifdef POPPLER_NEW_ERRORAPI
911
 
      error(errSyntaxError, getPos(), "Invalid soft mask in ExtGState");
912
 
#else
913
 
      error(getPos(), const_cast<char*>("Invalid soft mask in ExtGState"));
914
 
#endif
915
 
    }
916
 
  }
917
 
  obj2.free();
918
 
 
919
 
  obj1.free();
920
 
}
921
 
 
922
 
void PdfParser::doSoftMask(Object *str, GBool alpha,
923
 
                     GfxColorSpace *blendingColorSpace,
924
 
                     GBool isolated, GBool knockout,
925
 
                     Function *transferFunc, GfxColor *backdropColor) {
926
 
  Dict *dict, *resDict;
927
 
  double m[6], bbox[4];
928
 
  Object obj1, obj2;
929
 
  int i;
930
 
 
931
 
  // check for excessive recursion
932
 
  if (formDepth > 20) {
933
 
    return;
934
 
  }
935
 
 
936
 
  // get stream dict
937
 
  dict = str->streamGetDict();
938
 
 
939
 
  // check form type
940
 
  dict->lookup(const_cast<char*>("FormType"), &obj1);
941
 
  if (!(obj1.isNull() || (obj1.isInt() && obj1.getInt() == 1))) {
942
 
#ifdef POPPLER_NEW_ERRORAPI
943
 
    error(errSyntaxError, getPos(), "Unknown form type");
944
 
#else
945
 
    error(getPos(), const_cast<char*>("Unknown form type"));
946
 
#endif
947
 
  }
948
 
  obj1.free();
949
 
 
950
 
  // get bounding box
951
 
  dict->lookup(const_cast<char*>("BBox"), &obj1);
952
 
  if (!obj1.isArray()) {
953
 
    obj1.free();
954
 
#ifdef POPPLER_NEW_ERRORAPI
955
 
    error(errSyntaxError, getPos(), "Bad form bounding box");
956
 
#else
957
 
    error(getPos(), const_cast<char*>("Bad form bounding box"));
958
 
#endif
959
 
    return;
960
 
  }
961
 
  for (i = 0; i < 4; ++i) {
962
 
    obj1.arrayGet(i, &obj2);
963
 
    bbox[i] = obj2.getNum();
964
 
    obj2.free();
965
 
  }
966
 
  obj1.free();
967
 
 
968
 
  // get matrix
969
 
  dict->lookup(const_cast<char*>("Matrix"), &obj1);
970
 
  if (obj1.isArray()) {
971
 
    for (i = 0; i < 6; ++i) {
972
 
      obj1.arrayGet(i, &obj2);
973
 
      m[i] = obj2.getNum();
974
 
      obj2.free();
975
 
    }
976
 
  } else {
977
 
    m[0] = 1; m[1] = 0;
978
 
    m[2] = 0; m[3] = 1;
979
 
    m[4] = 0; m[5] = 0;
980
 
  }
981
 
  obj1.free();
982
 
 
983
 
  // get resources
984
 
  dict->lookup(const_cast<char*>("Resources"), &obj1);
985
 
  resDict = obj1.isDict() ? obj1.getDict() : (Dict *)NULL;
986
 
 
987
 
  // draw it
988
 
  ++formDepth;
989
 
  doForm1(str, resDict, m, bbox, gTrue, gTrue,
990
 
          blendingColorSpace, isolated, knockout,
991
 
          alpha, transferFunc, backdropColor);
992
 
  --formDepth;
993
 
 
994
 
  if (blendingColorSpace) {
995
 
    delete blendingColorSpace;
996
 
  }
997
 
  obj1.free();
998
 
}
999
 
 
1000
 
void PdfParser::opSetRenderingIntent(Object args[], int numArgs) {
1001
 
}
1002
 
 
1003
 
//------------------------------------------------------------------------
1004
 
// color operators
1005
 
//------------------------------------------------------------------------
1006
 
 
1007
 
void PdfParser::opSetFillGray(Object args[], int numArgs) {
1008
 
  GfxColor color;
1009
 
 
1010
 
  state->setFillPattern(NULL);
1011
 
  state->setFillColorSpace(new GfxDeviceGrayColorSpace());
1012
 
  color.c[0] = dblToCol(args[0].getNum());
1013
 
  state->setFillColor(&color);
1014
 
  builder->updateStyle(state);
1015
 
}
1016
 
 
1017
 
void PdfParser::opSetStrokeGray(Object args[], int numArgs) {
1018
 
  GfxColor color;
1019
 
 
1020
 
  state->setStrokePattern(NULL);
1021
 
  state->setStrokeColorSpace(new GfxDeviceGrayColorSpace());
1022
 
  color.c[0] = dblToCol(args[0].getNum());
1023
 
  state->setStrokeColor(&color);
1024
 
  builder->updateStyle(state);
1025
 
}
1026
 
 
1027
 
void PdfParser::opSetFillCMYKColor(Object args[], int numArgs) {
1028
 
  GfxColor color;
1029
 
  int i;
1030
 
 
1031
 
  state->setFillPattern(NULL);
1032
 
  state->setFillColorSpace(new GfxDeviceCMYKColorSpace());
1033
 
  for (i = 0; i < 4; ++i) {
1034
 
    color.c[i] = dblToCol(args[i].getNum());
1035
 
  }
1036
 
  state->setFillColor(&color);
1037
 
  builder->updateStyle(state);
1038
 
}
1039
 
 
1040
 
void PdfParser::opSetStrokeCMYKColor(Object args[], int numArgs) {
1041
 
  GfxColor color;
1042
 
  int i;
1043
 
 
1044
 
  state->setStrokePattern(NULL);
1045
 
  state->setStrokeColorSpace(new GfxDeviceCMYKColorSpace());
1046
 
  for (i = 0; i < 4; ++i) {
1047
 
    color.c[i] = dblToCol(args[i].getNum());
1048
 
  }
1049
 
  state->setStrokeColor(&color);
1050
 
  builder->updateStyle(state);
1051
 
}
1052
 
 
1053
 
void PdfParser::opSetFillRGBColor(Object args[], int numArgs) {
1054
 
  GfxColor color;
1055
 
  int i;
1056
 
 
1057
 
  state->setFillPattern(NULL);
1058
 
  state->setFillColorSpace(new GfxDeviceRGBColorSpace());
1059
 
  for (i = 0; i < 3; ++i) {
1060
 
    color.c[i] = dblToCol(args[i].getNum());
1061
 
  }
1062
 
  state->setFillColor(&color);
1063
 
  builder->updateStyle(state);
1064
 
}
1065
 
 
1066
 
void PdfParser::opSetStrokeRGBColor(Object args[], int numArgs) {
1067
 
  GfxColor color;
1068
 
  int i;
1069
 
 
1070
 
  state->setStrokePattern(NULL);
1071
 
  state->setStrokeColorSpace(new GfxDeviceRGBColorSpace());
1072
 
  for (i = 0; i < 3; ++i) {
1073
 
    color.c[i] = dblToCol(args[i].getNum());
1074
 
  }
1075
 
  state->setStrokeColor(&color);
1076
 
  builder->updateStyle(state);
1077
 
}
1078
 
 
1079
 
void PdfParser::opSetFillColorSpace(Object args[], int numArgs) {
1080
 
  Object obj;
1081
 
  GfxColorSpace *colorSpace;
1082
 
  GfxColor color;
1083
 
 
1084
 
  state->setFillPattern(NULL);
1085
 
  res->lookupColorSpace(args[0].getName(), &obj);
1086
 
#if defined(POPPLER_NEW_COLOR_SPACE_API) || defined(POPPLER_NEW_ERRORAPI)
1087
 
  if (obj.isNull()) {
1088
 
    colorSpace = GfxColorSpace::parse(&args[0], NULL);
1089
 
  } else {
1090
 
    colorSpace = GfxColorSpace::parse(&obj, NULL);
1091
 
  }
1092
 
#else
1093
 
  if (obj.isNull()) {
1094
 
    colorSpace = GfxColorSpace::parse(&args[0]);
1095
 
  } else {
1096
 
    colorSpace = GfxColorSpace::parse(&obj);
1097
 
  }
1098
 
#endif
1099
 
  obj.free();
1100
 
  if (colorSpace) {
1101
 
    state->setFillColorSpace(colorSpace);
1102
 
    colorSpace->getDefaultColor(&color);
1103
 
    state->setFillColor(&color);
1104
 
    builder->updateStyle(state);
1105
 
  } else {
1106
 
#ifdef POPPLER_NEW_ERRORAPI
1107
 
    error(errSyntaxError, getPos(), "Bad color space (fill)");
1108
 
#else
1109
 
    error(getPos(), const_cast<char*>("Bad color space (fill)"));
1110
 
#endif
1111
 
  }
1112
 
}
1113
 
 
1114
 
void PdfParser::opSetStrokeColorSpace(Object args[], int numArgs) {
1115
 
  Object obj;
1116
 
  GfxColorSpace *colorSpace;
1117
 
  GfxColor color;
1118
 
 
1119
 
  state->setStrokePattern(NULL);
1120
 
  res->lookupColorSpace(args[0].getName(), &obj);
1121
 
#if defined(POPPLER_NEW_COLOR_SPACE_API) || defined(POPPLER_NEW_ERRORAPI)
1122
 
  if (obj.isNull()) {
1123
 
    colorSpace = GfxColorSpace::parse(&args[0], NULL);
1124
 
  } else {
1125
 
    colorSpace = GfxColorSpace::parse(&obj, NULL);
1126
 
  }
1127
 
#else
1128
 
  if (obj.isNull()) {
1129
 
    colorSpace = GfxColorSpace::parse(&args[0]);
1130
 
  } else {
1131
 
    colorSpace = GfxColorSpace::parse(&obj);
1132
 
  }
1133
 
#endif
1134
 
  obj.free();
1135
 
  if (colorSpace) {
1136
 
    state->setStrokeColorSpace(colorSpace);
1137
 
    colorSpace->getDefaultColor(&color);
1138
 
    state->setStrokeColor(&color);
1139
 
    builder->updateStyle(state);
1140
 
  } else {
1141
 
#ifdef POPPLER_NEW_ERRORAPI
1142
 
    error(errSyntaxError, getPos(), "Bad color space (stroke)");
1143
 
#else
1144
 
    error(getPos(), const_cast<char*>("Bad color space (stroke)"));
1145
 
#endif
1146
 
  }
1147
 
}
1148
 
 
1149
 
void PdfParser::opSetFillColor(Object args[], int numArgs) {
1150
 
  GfxColor color;
1151
 
  int i;
1152
 
 
1153
 
  if (numArgs != state->getFillColorSpace()->getNComps()) {
1154
 
#ifdef POPPLER_NEW_ERRORAPI
1155
 
    error(errSyntaxError, getPos(), "Incorrect number of arguments in 'sc' command");
1156
 
#else
1157
 
    error(getPos(), const_cast<char*>("Incorrect number of arguments in 'sc' command"));
1158
 
#endif
1159
 
    return;
1160
 
  }
1161
 
  state->setFillPattern(NULL);
1162
 
  for (i = 0; i < numArgs; ++i) {
1163
 
    color.c[i] = dblToCol(args[i].getNum());
1164
 
  }
1165
 
  state->setFillColor(&color);
1166
 
  builder->updateStyle(state);
1167
 
}
1168
 
 
1169
 
void PdfParser::opSetStrokeColor(Object args[], int numArgs) {
1170
 
  GfxColor color;
1171
 
  int i;
1172
 
 
1173
 
  if (numArgs != state->getStrokeColorSpace()->getNComps()) {
1174
 
#ifdef POPPLER_NEW_ERRORAPI
1175
 
    error(errSyntaxError, getPos(), "Incorrect number of arguments in 'SC' command");
1176
 
#else
1177
 
    error(getPos(), const_cast<char*>("Incorrect number of arguments in 'SC' command"));
1178
 
#endif
1179
 
    return;
1180
 
  }
1181
 
  state->setStrokePattern(NULL);
1182
 
  for (i = 0; i < numArgs; ++i) {
1183
 
    color.c[i] = dblToCol(args[i].getNum());
1184
 
  }
1185
 
  state->setStrokeColor(&color);
1186
 
  builder->updateStyle(state);
1187
 
}
1188
 
 
1189
 
void PdfParser::opSetFillColorN(Object args[], int numArgs) {
1190
 
  GfxColor color;
1191
 
  GfxPattern *pattern;
1192
 
  int i;
1193
 
 
1194
 
  if (state->getFillColorSpace()->getMode() == csPattern) {
1195
 
    if (numArgs > 1) {
1196
 
      if (!((GfxPatternColorSpace *)state->getFillColorSpace())->getUnder() ||
1197
 
          numArgs - 1 != ((GfxPatternColorSpace *)state->getFillColorSpace())
1198
 
                             ->getUnder()->getNComps()) {
1199
 
#ifdef POPPLER_NEW_ERRORAPI
1200
 
        error(errSyntaxError, getPos(), "Incorrect number of arguments in 'scn' command");
1201
 
#else
1202
 
        error(getPos(), const_cast<char*>("Incorrect number of arguments in 'scn' command"));
1203
 
#endif
1204
 
        return;
1205
 
      }
1206
 
      for (i = 0; i < numArgs - 1 && i < gfxColorMaxComps; ++i) {
1207
 
        if (args[i].isNum()) {
1208
 
          color.c[i] = dblToCol(args[i].getNum());
1209
 
        }
1210
 
      }
1211
 
      state->setFillColor(&color);
1212
 
      builder->updateStyle(state);
1213
 
    }
1214
 
#if defined(POPPLER_NEW_COLOR_SPACE_API) || defined(POPPLER_NEW_ERRORAPI)
1215
 
    if (args[numArgs-1].isName() &&
1216
 
        (pattern = res->lookupPattern(args[numArgs-1].getName(), NULL))) {
1217
 
      state->setFillPattern(pattern);
1218
 
      builder->updateStyle(state);
1219
 
    }
1220
 
#else
1221
 
    if (args[numArgs-1].isName() &&
1222
 
        (pattern = res->lookupPattern(args[numArgs-1].getName()))) {
1223
 
      state->setFillPattern(pattern);
1224
 
      builder->updateStyle(state);
1225
 
    }
1226
 
#endif
1227
 
 
1228
 
  } else {
1229
 
    if (numArgs != state->getFillColorSpace()->getNComps()) {
1230
 
#ifdef POPPLER_NEW_ERRORAPI
1231
 
      error(errSyntaxError, getPos(), "Incorrect number of arguments in 'scn' command");
1232
 
#else
1233
 
      error(getPos(), const_cast<char*>("Incorrect number of arguments in 'scn' command"));
1234
 
#endif
1235
 
      return;
1236
 
    }
1237
 
    state->setFillPattern(NULL);
1238
 
    for (i = 0; i < numArgs && i < gfxColorMaxComps; ++i) {
1239
 
      if (args[i].isNum()) {
1240
 
        color.c[i] = dblToCol(args[i].getNum());
1241
 
      }
1242
 
    }
1243
 
    state->setFillColor(&color);
1244
 
    builder->updateStyle(state);
1245
 
  }
1246
 
}
1247
 
 
1248
 
void PdfParser::opSetStrokeColorN(Object args[], int numArgs) {
1249
 
  GfxColor color;
1250
 
  GfxPattern *pattern;
1251
 
  int i;
1252
 
 
1253
 
  if (state->getStrokeColorSpace()->getMode() == csPattern) {
1254
 
    if (numArgs > 1) {
1255
 
      if (!((GfxPatternColorSpace *)state->getStrokeColorSpace())
1256
 
               ->getUnder() ||
1257
 
          numArgs - 1 != ((GfxPatternColorSpace *)state->getStrokeColorSpace())
1258
 
                             ->getUnder()->getNComps()) {
1259
 
#ifdef POPPLER_NEW_ERRORAPI
1260
 
        error(errSyntaxError, getPos(), "Incorrect number of arguments in 'SCN' command");
1261
 
#else
1262
 
        error(getPos(), const_cast<char*>("Incorrect number of arguments in 'SCN' command"));
1263
 
#endif
1264
 
        return;
1265
 
      }
1266
 
      for (i = 0; i < numArgs - 1 && i < gfxColorMaxComps; ++i) {
1267
 
        if (args[i].isNum()) {
1268
 
          color.c[i] = dblToCol(args[i].getNum());
1269
 
        }
1270
 
      }
1271
 
      state->setStrokeColor(&color);
1272
 
      builder->updateStyle(state);
1273
 
    }
1274
 
#if defined(POPPLER_NEW_COLOR_SPACE_API) || defined(POPPLER_NEW_ERRORAPI)
1275
 
    if (args[numArgs-1].isName() &&
1276
 
        (pattern = res->lookupPattern(args[numArgs-1].getName(), NULL))) {
1277
 
      state->setStrokePattern(pattern);
1278
 
      builder->updateStyle(state);
1279
 
    }
1280
 
#else
1281
 
    if (args[numArgs-1].isName() &&
1282
 
        (pattern = res->lookupPattern(args[numArgs-1].getName()))) {
1283
 
      state->setStrokePattern(pattern);
1284
 
      builder->updateStyle(state);
1285
 
    }
1286
 
#endif
1287
 
 
1288
 
  } else {
1289
 
    if (numArgs != state->getStrokeColorSpace()->getNComps()) {
1290
 
#ifdef POPPLER_NEW_ERRORAPI
1291
 
      error(errSyntaxError, getPos(), "Incorrect number of arguments in 'SCN' command");
1292
 
#else
1293
 
      error(getPos(), const_cast<char*>("Incorrect number of arguments in 'SCN' command"));
1294
 
#endif
1295
 
      return;
1296
 
    }
1297
 
    state->setStrokePattern(NULL);
1298
 
    for (i = 0; i < numArgs && i < gfxColorMaxComps; ++i) {
1299
 
      if (args[i].isNum()) {
1300
 
        color.c[i] = dblToCol(args[i].getNum());
1301
 
      }
1302
 
    }
1303
 
    state->setStrokeColor(&color);
1304
 
    builder->updateStyle(state);
1305
 
  }
1306
 
}
1307
 
 
1308
 
//------------------------------------------------------------------------
1309
 
// path segment operators
1310
 
//------------------------------------------------------------------------
1311
 
 
1312
 
void PdfParser::opMoveTo(Object args[], int numArgs) {
1313
 
  state->moveTo(args[0].getNum(), args[1].getNum());
1314
 
}
1315
 
 
1316
 
void PdfParser::opLineTo(Object args[], int numArgs) {
1317
 
  if (!state->isCurPt()) {
1318
 
#ifdef POPPLER_NEW_ERRORAPI
1319
 
    error(errSyntaxError, getPos(), "No current point in lineto");
1320
 
#else
1321
 
    error(getPos(), const_cast<char*>("No current point in lineto"));
1322
 
#endif
1323
 
    return;
1324
 
  }
1325
 
  state->lineTo(args[0].getNum(), args[1].getNum());
1326
 
}
1327
 
 
1328
 
void PdfParser::opCurveTo(Object args[], int numArgs) {
1329
 
  double x1, y1, x2, y2, x3, y3;
1330
 
 
1331
 
  if (!state->isCurPt()) {
1332
 
#ifdef POPPLER_NEW_ERRORAPI
1333
 
    error(errSyntaxError, getPos(), "No current point in curveto");
1334
 
#else
1335
 
    error(getPos(), const_cast<char*>("No current point in curveto"));
1336
 
#endif
1337
 
    return;
1338
 
  }
1339
 
  x1 = args[0].getNum();
1340
 
  y1 = args[1].getNum();
1341
 
  x2 = args[2].getNum();
1342
 
  y2 = args[3].getNum();
1343
 
  x3 = args[4].getNum();
1344
 
  y3 = args[5].getNum();
1345
 
  state->curveTo(x1, y1, x2, y2, x3, y3);
1346
 
}
1347
 
 
1348
 
void PdfParser::opCurveTo1(Object args[], int numArgs) {
1349
 
  double x1, y1, x2, y2, x3, y3;
1350
 
 
1351
 
  if (!state->isCurPt()) {
1352
 
#ifdef POPPLER_NEW_ERRORAPI
1353
 
    error(errSyntaxError, getPos(), "No current point in curveto1");
1354
 
#else
1355
 
    error(getPos(), const_cast<char*>("No current point in curveto1"));
1356
 
#endif
1357
 
    return;
1358
 
  }
1359
 
  x1 = state->getCurX();
1360
 
  y1 = state->getCurY();
1361
 
  x2 = args[0].getNum();
1362
 
  y2 = args[1].getNum();
1363
 
  x3 = args[2].getNum();
1364
 
  y3 = args[3].getNum();
1365
 
  state->curveTo(x1, y1, x2, y2, x3, y3);
1366
 
}
1367
 
 
1368
 
void PdfParser::opCurveTo2(Object args[], int numArgs) {
1369
 
  double x1, y1, x2, y2, x3, y3;
1370
 
 
1371
 
  if (!state->isCurPt()) {
1372
 
#ifdef POPPLER_NEW_ERRORAPI
1373
 
    error(errSyntaxError, getPos(), "No current point in curveto2");
1374
 
#else
1375
 
    error(getPos(), const_cast<char*>("No current point in curveto2"));
1376
 
#endif
1377
 
    return;
1378
 
  }
1379
 
  x1 = args[0].getNum();
1380
 
  y1 = args[1].getNum();
1381
 
  x2 = args[2].getNum();
1382
 
  y2 = args[3].getNum();
1383
 
  x3 = x2;
1384
 
  y3 = y2;
1385
 
  state->curveTo(x1, y1, x2, y2, x3, y3);
1386
 
}
1387
 
 
1388
 
void PdfParser::opRectangle(Object args[], int numArgs) {
1389
 
  double x, y, w, h;
1390
 
 
1391
 
  x = args[0].getNum();
1392
 
  y = args[1].getNum();
1393
 
  w = args[2].getNum();
1394
 
  h = args[3].getNum();
1395
 
  state->moveTo(x, y);
1396
 
  state->lineTo(x + w, y);
1397
 
  state->lineTo(x + w, y + h);
1398
 
  state->lineTo(x, y + h);
1399
 
  state->closePath();
1400
 
}
1401
 
 
1402
 
void PdfParser::opClosePath(Object args[], int numArgs) {
1403
 
  if (!state->isCurPt()) {
1404
 
#ifdef POPPLER_NEW_ERRORAPI
1405
 
    error(errSyntaxError, getPos(), "No current point in closepath");
1406
 
#else
1407
 
    error(getPos(), const_cast<char*>("No current point in closepath"));
1408
 
#endif
1409
 
    return;
1410
 
  }
1411
 
  state->closePath();
1412
 
}
1413
 
 
1414
 
//------------------------------------------------------------------------
1415
 
// path painting operators
1416
 
//------------------------------------------------------------------------
1417
 
 
1418
 
void PdfParser::opEndPath(Object args[], int numArgs) {
1419
 
  doEndPath();
1420
 
}
1421
 
 
1422
 
void PdfParser::opStroke(Object args[], int numArgs) {
1423
 
  if (!state->isCurPt()) {
1424
 
    //error(getPos(), const_cast<char*>("No path in stroke"));
1425
 
    return;
1426
 
  }
1427
 
  if (state->isPath()) {
1428
 
    if (state->getStrokeColorSpace()->getMode() == csPattern &&
1429
 
        !builder->isPatternTypeSupported(state->getStrokePattern())) {
1430
 
          doPatternStrokeFallback();
1431
 
    } else {
1432
 
      builder->addPath(state, false, true);
1433
 
    }
1434
 
  }
1435
 
  doEndPath();
1436
 
}
1437
 
 
1438
 
void PdfParser::opCloseStroke(Object * /*args[]*/, int /*numArgs*/) {
1439
 
  if (!state->isCurPt()) {
1440
 
    //error(getPos(), const_cast<char*>("No path in closepath/stroke"));
1441
 
    return;
1442
 
  }
1443
 
  state->closePath();
1444
 
  if (state->isPath()) {
1445
 
    if (state->getStrokeColorSpace()->getMode() == csPattern &&
1446
 
        !builder->isPatternTypeSupported(state->getStrokePattern())) {
1447
 
      doPatternStrokeFallback();
1448
 
    } else {
1449
 
      builder->addPath(state, false, true);
1450
 
    }
1451
 
  }
1452
 
  doEndPath();
1453
 
}
1454
 
 
1455
 
void PdfParser::opFill(Object args[], int numArgs) {
1456
 
  if (!state->isCurPt()) {
1457
 
    //error(getPos(), const_cast<char*>("No path in fill"));
1458
 
    return;
1459
 
  }
1460
 
  if (state->isPath()) {
1461
 
    if (state->getFillColorSpace()->getMode() == csPattern &&
1462
 
        !builder->isPatternTypeSupported(state->getFillPattern())) {
1463
 
      doPatternFillFallback(gFalse);
1464
 
    } else {
1465
 
      builder->addPath(state, true, false);
1466
 
    }
1467
 
  }
1468
 
  doEndPath();
1469
 
}
1470
 
 
1471
 
void PdfParser::opEOFill(Object args[], int numArgs) {
1472
 
  if (!state->isCurPt()) {
1473
 
    //error(getPos(), const_cast<char*>("No path in eofill"));
1474
 
    return;
1475
 
  }
1476
 
  if (state->isPath()) {
1477
 
    if (state->getFillColorSpace()->getMode() == csPattern &&
1478
 
        !builder->isPatternTypeSupported(state->getFillPattern())) {
1479
 
      doPatternFillFallback(gTrue);
1480
 
    } else {
1481
 
      builder->addPath(state, true, false, true);
1482
 
    }
1483
 
  }
1484
 
  doEndPath();
1485
 
}
1486
 
 
1487
 
void PdfParser::opFillStroke(Object args[], int numArgs) {
1488
 
  if (!state->isCurPt()) {
1489
 
    //error(getPos(), const_cast<char*>("No path in fill/stroke"));
1490
 
    return;
1491
 
  }
1492
 
  if (state->isPath()) {
1493
 
    doFillAndStroke(gFalse);
1494
 
  } else {
1495
 
    builder->addPath(state, true, true);
1496
 
  }
1497
 
  doEndPath();
1498
 
}
1499
 
 
1500
 
void PdfParser::opCloseFillStroke(Object args[], int numArgs) {
1501
 
  if (!state->isCurPt()) {
1502
 
    //error(getPos(), const_cast<char*>("No path in closepath/fill/stroke"));
1503
 
    return;
1504
 
  }
1505
 
  if (state->isPath()) {
1506
 
    state->closePath();
1507
 
    doFillAndStroke(gFalse);
1508
 
  }
1509
 
  doEndPath();
1510
 
}
1511
 
 
1512
 
void PdfParser::opEOFillStroke(Object args[], int numArgs) {
1513
 
  if (!state->isCurPt()) {
1514
 
    //error(getPos(), const_cast<char*>("No path in eofill/stroke"));
1515
 
    return;
1516
 
  }
1517
 
  if (state->isPath()) {
1518
 
    doFillAndStroke(gTrue);
1519
 
  }
1520
 
  doEndPath();
1521
 
}
1522
 
 
1523
 
void PdfParser::opCloseEOFillStroke(Object args[], int numArgs) {
1524
 
  if (!state->isCurPt()) {
1525
 
    //error(getPos(), const_cast<char*>("No path in closepath/eofill/stroke"));
1526
 
    return;
1527
 
  }
1528
 
  if (state->isPath()) {
1529
 
    state->closePath();
1530
 
    doFillAndStroke(gTrue);
1531
 
  }
1532
 
  doEndPath();
1533
 
}
1534
 
 
1535
 
void PdfParser::doFillAndStroke(GBool eoFill) {
1536
 
    GBool fillOk = gTrue, strokeOk = gTrue;
1537
 
    if (state->getFillColorSpace()->getMode() == csPattern &&
1538
 
        !builder->isPatternTypeSupported(state->getFillPattern())) {
1539
 
        fillOk = gFalse;
1540
 
    }
1541
 
    if (state->getStrokeColorSpace()->getMode() == csPattern &&
1542
 
        !builder->isPatternTypeSupported(state->getStrokePattern())) {
1543
 
        strokeOk = gFalse;
1544
 
    }
1545
 
    if (fillOk && strokeOk) {
1546
 
        builder->addPath(state, true, true, eoFill);
1547
 
    } else {
1548
 
        doPatternFillFallback(eoFill);
1549
 
        doPatternStrokeFallback();
1550
 
    }
1551
 
}
1552
 
 
1553
 
void PdfParser::doPatternFillFallback(GBool eoFill) {
1554
 
  GfxPattern *pattern;
1555
 
 
1556
 
  if (!(pattern = state->getFillPattern())) {
1557
 
    return;
1558
 
  }
1559
 
  switch (pattern->getType()) {
1560
 
  case 1:
1561
 
    break;
1562
 
  case 2:
1563
 
    doShadingPatternFillFallback((GfxShadingPattern *)pattern, gFalse, eoFill);
1564
 
    break;
1565
 
  default:
1566
 
#ifdef POPPLER_NEW_ERRORAPI
1567
 
    error(errUnimplemented, getPos(), "Unimplemented pattern type (%d) in fill",
1568
 
#else
1569
 
    error(getPos(), const_cast<char*>("Unimplemented pattern type (%d) in fill"),
1570
 
#endif
1571
 
          pattern->getType());
1572
 
    break;
1573
 
  }
1574
 
}
1575
 
 
1576
 
void PdfParser::doPatternStrokeFallback() {
1577
 
  GfxPattern *pattern;
1578
 
 
1579
 
  if (!(pattern = state->getStrokePattern())) {
1580
 
    return;
1581
 
  }
1582
 
  switch (pattern->getType()) {
1583
 
  case 1:
1584
 
    break;
1585
 
  case 2:
1586
 
    doShadingPatternFillFallback((GfxShadingPattern *)pattern, gTrue, gFalse);
1587
 
    break;
1588
 
  default:
1589
 
#ifdef POPPLER_NEW_ERRORAPI
1590
 
    error(errUnimplemented, getPos(), "Unimplemented pattern type ({0:d}) in stroke",
1591
 
#else
1592
 
    error(getPos(), const_cast<char*>("Unimplemented pattern type (%d) in stroke"),
1593
 
#endif
1594
 
          pattern->getType());
1595
 
    break;
1596
 
  }
1597
 
}
1598
 
 
1599
 
void PdfParser::doShadingPatternFillFallback(GfxShadingPattern *sPat,
1600
 
                                             GBool stroke, GBool eoFill) {
1601
 
  GfxShading *shading;
1602
 
  GfxPath *savedPath;
1603
 
  double *ctm, *btm, *ptm;
1604
 
  double m[6], ictm[6], m1[6];
1605
 
  double xMin, yMin, xMax, yMax;
1606
 
  double det;
1607
 
 
1608
 
  shading = sPat->getShading();
1609
 
 
1610
 
  // save current graphics state
1611
 
  savedPath = state->getPath()->copy();
1612
 
  saveState();
1613
 
 
1614
 
  // clip to bbox
1615
 
  if (0 ){//shading->getHasBBox()) {
1616
 
    shading->getBBox(&xMin, &yMin, &xMax, &yMax);
1617
 
    state->moveTo(xMin, yMin);
1618
 
    state->lineTo(xMax, yMin);
1619
 
    state->lineTo(xMax, yMax);
1620
 
    state->lineTo(xMin, yMax);
1621
 
    state->closePath();
1622
 
    state->clip();
1623
 
    //builder->clip(state);
1624
 
    state->setPath(savedPath->copy());
1625
 
  }
1626
 
 
1627
 
  // clip to current path
1628
 
  if (stroke) {
1629
 
    state->clipToStrokePath();
1630
 
    //out->clipToStrokePath(state);
1631
 
  } else {
1632
 
    state->clip();
1633
 
    if (eoFill) {
1634
 
      builder->setClipPath(state, true);
1635
 
    } else {
1636
 
      builder->setClipPath(state);
1637
 
    }
1638
 
  }
1639
 
 
1640
 
  // set the color space
1641
 
  state->setFillColorSpace(shading->getColorSpace()->copy());
1642
 
 
1643
 
  // background color fill
1644
 
  if (shading->getHasBackground()) {
1645
 
    state->setFillColor(shading->getBackground());
1646
 
    builder->addPath(state, true, false);
1647
 
  }
1648
 
  state->clearPath();
1649
 
 
1650
 
  // construct a (pattern space) -> (current space) transform matrix
1651
 
  ctm = state->getCTM();
1652
 
  btm = baseMatrix;
1653
 
  ptm = sPat->getMatrix();
1654
 
  // iCTM = invert CTM
1655
 
  det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]);
1656
 
  ictm[0] = ctm[3] * det;
1657
 
  ictm[1] = -ctm[1] * det;
1658
 
  ictm[2] = -ctm[2] * det;
1659
 
  ictm[3] = ctm[0] * det;
1660
 
  ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det;
1661
 
  ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det;
1662
 
  // m1 = PTM * BTM = PTM * base transform matrix
1663
 
  m1[0] = ptm[0] * btm[0] + ptm[1] * btm[2];
1664
 
  m1[1] = ptm[0] * btm[1] + ptm[1] * btm[3];
1665
 
  m1[2] = ptm[2] * btm[0] + ptm[3] * btm[2];
1666
 
  m1[3] = ptm[2] * btm[1] + ptm[3] * btm[3];
1667
 
  m1[4] = ptm[4] * btm[0] + ptm[5] * btm[2] + btm[4];
1668
 
  m1[5] = ptm[4] * btm[1] + ptm[5] * btm[3] + btm[5];
1669
 
  // m = m1 * iCTM = (PTM * BTM) * (iCTM)
1670
 
  m[0] = m1[0] * ictm[0] + m1[1] * ictm[2];
1671
 
  m[1] = m1[0] * ictm[1] + m1[1] * ictm[3];
1672
 
  m[2] = m1[2] * ictm[0] + m1[3] * ictm[2];
1673
 
  m[3] = m1[2] * ictm[1] + m1[3] * ictm[3];
1674
 
  m[4] = m1[4] * ictm[0] + m1[5] * ictm[2] + ictm[4];
1675
 
  m[5] = m1[4] * ictm[1] + m1[5] * ictm[3] + ictm[5];
1676
 
 
1677
 
  // set the new matrix
1678
 
  state->concatCTM(m[0], m[1], m[2], m[3], m[4], m[5]);
1679
 
  builder->setTransform(m[0], m[1], m[2], m[3], m[4], m[5]);
1680
 
 
1681
 
  // do shading type-specific operations
1682
 
  switch (shading->getType()) {
1683
 
  case 1:
1684
 
    doFunctionShFill((GfxFunctionShading *)shading);
1685
 
    break;
1686
 
  case 2:
1687
 
  case 3:
1688
 
    // no need to implement these
1689
 
    break;
1690
 
  case 4:
1691
 
  case 5:
1692
 
    doGouraudTriangleShFill((GfxGouraudTriangleShading *)shading);
1693
 
    break;
1694
 
  case 6:
1695
 
  case 7:
1696
 
    doPatchMeshShFill((GfxPatchMeshShading *)shading);
1697
 
    break;
1698
 
  }
1699
 
 
1700
 
  // restore graphics state
1701
 
  restoreState();
1702
 
  state->setPath(savedPath);
1703
 
}
1704
 
 
1705
 
void PdfParser::opShFill(Object args[], int numArgs) {
1706
 
  GfxShading *shading;
1707
 
  GfxPath *savedPath = NULL;
1708
 
  double xMin, yMin, xMax, yMax;
1709
 
  double gradientTransform[6];
1710
 
  double *matrix = NULL;
1711
 
  GBool savedState = gFalse;
1712
 
 
1713
 
#if defined(POPPLER_NEW_COLOR_SPACE_API) || defined(POPPLER_NEW_ERRORAPI)
1714
 
  if (!(shading = res->lookupShading(args[0].getName(), NULL))) {
1715
 
    return;
1716
 
  }
1717
 
#else
1718
 
  if (!(shading = res->lookupShading(args[0].getName()))) {
1719
 
    return;
1720
 
  }
1721
 
#endif
1722
 
 
1723
 
  // save current graphics state
1724
 
  if (shading->getType() != 2 && shading->getType() != 3) {
1725
 
    savedPath = state->getPath()->copy();
1726
 
    saveState();
1727
 
    savedState = gTrue;
1728
 
  } else {  // get gradient transform if possible
1729
 
      // check proper operator sequence
1730
 
      // first there should be one W(*) and then one 'cm' somewhere before 'sh'
1731
 
      GBool seenClip, seenConcat;
1732
 
      seenClip = (clipHistory->getClipPath() != NULL);
1733
 
      seenConcat = gFalse;
1734
 
      int i = 1;
1735
 
      while (i <= maxOperatorHistoryDepth) {
1736
 
        const char *opName = getPreviousOperator(i);
1737
 
        if (!strcmp(opName, "cm")) {
1738
 
          if (seenConcat) {   // more than one 'cm'
1739
 
            break;
1740
 
          } else {
1741
 
            seenConcat = gTrue;
1742
 
          }
1743
 
        }
1744
 
        i++;
1745
 
      }
1746
 
 
1747
 
      if (seenConcat && seenClip) {
1748
 
        if (builder->getTransform(gradientTransform)) {
1749
 
          matrix = (double*)&gradientTransform;
1750
 
          builder->setTransform(1.0, 0.0, 0.0, 1.0, 0.0, 0.0);  // remove transform
1751
 
        }
1752
 
      }
1753
 
  }
1754
 
 
1755
 
  // clip to bbox
1756
 
  if (shading->getHasBBox()) {
1757
 
    shading->getBBox(&xMin, &yMin, &xMax, &yMax);
1758
 
    state->moveTo(xMin, yMin);
1759
 
    state->lineTo(xMax, yMin);
1760
 
    state->lineTo(xMax, yMax);
1761
 
    state->lineTo(xMin, yMax);
1762
 
    state->closePath();
1763
 
    state->clip();
1764
 
    if (savedState)
1765
 
      builder->setClipPath(state);
1766
 
    else
1767
 
      builder->clip(state);
1768
 
    state->clearPath();
1769
 
  }
1770
 
 
1771
 
  // set the color space
1772
 
  if (savedState)
1773
 
    state->setFillColorSpace(shading->getColorSpace()->copy());
1774
 
 
1775
 
  // do shading type-specific operations
1776
 
  switch (shading->getType()) {
1777
 
  case 1:
1778
 
    doFunctionShFill((GfxFunctionShading *)shading);
1779
 
    break;
1780
 
  case 2:
1781
 
  case 3:
1782
 
    if (clipHistory->getClipPath()) {
1783
 
      builder->addShadedFill(shading, matrix, clipHistory->getClipPath(),
1784
 
                             clipHistory->getClipType() == clipEO ? true : false);
1785
 
    }
1786
 
    break;
1787
 
  case 4:
1788
 
  case 5:
1789
 
    doGouraudTriangleShFill((GfxGouraudTriangleShading *)shading);
1790
 
    break;
1791
 
  case 6:
1792
 
  case 7:
1793
 
    doPatchMeshShFill((GfxPatchMeshShading *)shading);
1794
 
    break;
1795
 
  }
1796
 
 
1797
 
  // restore graphics state
1798
 
  if (savedState) {
1799
 
    restoreState();
1800
 
    state->setPath(savedPath);
1801
 
  }
1802
 
 
1803
 
  delete shading;
1804
 
}
1805
 
 
1806
 
void PdfParser::doFunctionShFill(GfxFunctionShading *shading) {
1807
 
  double x0, y0, x1, y1;
1808
 
  GfxColor colors[4];
1809
 
 
1810
 
  shading->getDomain(&x0, &y0, &x1, &y1);
1811
 
  shading->getColor(x0, y0, &colors[0]);
1812
 
  shading->getColor(x0, y1, &colors[1]);
1813
 
  shading->getColor(x1, y0, &colors[2]);
1814
 
  shading->getColor(x1, y1, &colors[3]);
1815
 
  doFunctionShFill1(shading, x0, y0, x1, y1, colors, 0);
1816
 
}
1817
 
 
1818
 
void PdfParser::doFunctionShFill1(GfxFunctionShading *shading,
1819
 
                            double x0, double y0,
1820
 
                            double x1, double y1,
1821
 
                            GfxColor *colors, int depth) {
1822
 
  GfxColor fillColor;
1823
 
  GfxColor color0M, color1M, colorM0, colorM1, colorMM;
1824
 
  GfxColor colors2[4];
1825
 
  double functionColorDelta = colorDeltas[pdfFunctionShading-1];
1826
 
  double *matrix;
1827
 
  double xM, yM;
1828
 
  int nComps, i, j;
1829
 
 
1830
 
  nComps = shading->getColorSpace()->getNComps();
1831
 
  matrix = shading->getMatrix();
1832
 
 
1833
 
  // compare the four corner colors
1834
 
  for (i = 0; i < 4; ++i) {
1835
 
    for (j = 0; j < nComps; ++j) {
1836
 
      if (abs(colors[i].c[j] - colors[(i+1)&3].c[j]) > functionColorDelta) {
1837
 
        break;
1838
 
      }
1839
 
    }
1840
 
    if (j < nComps) {
1841
 
      break;
1842
 
    }
1843
 
  }
1844
 
 
1845
 
  // center of the rectangle
1846
 
  xM = 0.5 * (x0 + x1);
1847
 
  yM = 0.5 * (y0 + y1);
1848
 
 
1849
 
  // the four corner colors are close (or we hit the recursive limit)
1850
 
  // -- fill the rectangle; but require at least one subdivision
1851
 
  // (depth==0) to avoid problems when the four outer corners of the
1852
 
  // shaded region are the same color
1853
 
  if ((i == 4 && depth > 0) || depth == maxDepths[pdfFunctionShading-1]) {
1854
 
 
1855
 
    // use the center color
1856
 
    shading->getColor(xM, yM, &fillColor);
1857
 
    state->setFillColor(&fillColor);
1858
 
 
1859
 
    // fill the rectangle
1860
 
    state->moveTo(x0 * matrix[0] + y0 * matrix[2] + matrix[4],
1861
 
                  x0 * matrix[1] + y0 * matrix[3] + matrix[5]);
1862
 
    state->lineTo(x1 * matrix[0] + y0 * matrix[2] + matrix[4],
1863
 
                  x1 * matrix[1] + y0 * matrix[3] + matrix[5]);
1864
 
    state->lineTo(x1 * matrix[0] + y1 * matrix[2] + matrix[4],
1865
 
                  x1 * matrix[1] + y1 * matrix[3] + matrix[5]);
1866
 
    state->lineTo(x0 * matrix[0] + y1 * matrix[2] + matrix[4],
1867
 
                  x0 * matrix[1] + y1 * matrix[3] + matrix[5]);
1868
 
    state->closePath();
1869
 
    builder->addPath(state, true, false);
1870
 
    state->clearPath();
1871
 
 
1872
 
  // the four corner colors are not close enough -- subdivide the
1873
 
  // rectangle
1874
 
  } else {
1875
 
 
1876
 
    // colors[0]       colorM0       colors[2]
1877
 
    //   (x0,y0)       (xM,y0)       (x1,y0)
1878
 
    //         +----------+----------+
1879
 
    //         |          |          |
1880
 
    //         |    UL    |    UR    |
1881
 
    // color0M |       colorMM       | color1M
1882
 
    // (x0,yM) +----------+----------+ (x1,yM)
1883
 
    //         |       (xM,yM)       |
1884
 
    //         |    LL    |    LR    |
1885
 
    //         |          |          |
1886
 
    //         +----------+----------+
1887
 
    // colors[1]       colorM1       colors[3]
1888
 
    //   (x0,y1)       (xM,y1)       (x1,y1)
1889
 
 
1890
 
    shading->getColor(x0, yM, &color0M);
1891
 
    shading->getColor(x1, yM, &color1M);
1892
 
    shading->getColor(xM, y0, &colorM0);
1893
 
    shading->getColor(xM, y1, &colorM1);
1894
 
    shading->getColor(xM, yM, &colorMM);
1895
 
 
1896
 
    // upper-left sub-rectangle
1897
 
    colors2[0] = colors[0];
1898
 
    colors2[1] = color0M;
1899
 
    colors2[2] = colorM0;
1900
 
    colors2[3] = colorMM;
1901
 
    doFunctionShFill1(shading, x0, y0, xM, yM, colors2, depth + 1);
1902
 
    
1903
 
    // lower-left sub-rectangle
1904
 
    colors2[0] = color0M;
1905
 
    colors2[1] = colors[1];
1906
 
    colors2[2] = colorMM;
1907
 
    colors2[3] = colorM1;
1908
 
    doFunctionShFill1(shading, x0, yM, xM, y1, colors2, depth + 1);
1909
 
    
1910
 
    // upper-right sub-rectangle
1911
 
    colors2[0] = colorM0;
1912
 
    colors2[1] = colorMM;
1913
 
    colors2[2] = colors[2];
1914
 
    colors2[3] = color1M;
1915
 
    doFunctionShFill1(shading, xM, y0, x1, yM, colors2, depth + 1);
1916
 
 
1917
 
    // lower-right sub-rectangle
1918
 
    colors2[0] = colorMM;
1919
 
    colors2[1] = colorM1;
1920
 
    colors2[2] = color1M;
1921
 
    colors2[3] = colors[3];
1922
 
    doFunctionShFill1(shading, xM, yM, x1, y1, colors2, depth + 1);
1923
 
  }
1924
 
}
1925
 
 
1926
 
void PdfParser::doGouraudTriangleShFill(GfxGouraudTriangleShading *shading) {
1927
 
  double x0, y0, x1, y1, x2, y2;
1928
 
  GfxColor color0, color1, color2;
1929
 
  int i;
1930
 
 
1931
 
  for (i = 0; i < shading->getNTriangles(); ++i) {
1932
 
    shading->getTriangle(i, &x0, &y0, &color0,
1933
 
                         &x1, &y1, &color1,
1934
 
                         &x2, &y2, &color2);
1935
 
    gouraudFillTriangle(x0, y0, &color0, x1, y1, &color1, x2, y2, &color2,
1936
 
                        shading->getColorSpace()->getNComps(), 0);
1937
 
  }
1938
 
}
1939
 
 
1940
 
void PdfParser::gouraudFillTriangle(double x0, double y0, GfxColor *color0,
1941
 
                              double x1, double y1, GfxColor *color1,
1942
 
                              double x2, double y2, GfxColor *color2,
1943
 
                              int nComps, int depth) {
1944
 
  double x01, y01, x12, y12, x20, y20;
1945
 
  double gouraudColorDelta = colorDeltas[pdfGouraudTriangleShading-1];
1946
 
  GfxColor color01, color12, color20;
1947
 
  int i;
1948
 
 
1949
 
  for (i = 0; i < nComps; ++i) {
1950
 
    if (abs(color0->c[i] - color1->c[i]) > gouraudColorDelta ||
1951
 
       abs(color1->c[i] - color2->c[i]) > gouraudColorDelta) {
1952
 
      break;
1953
 
    }
1954
 
  }
1955
 
  if (i == nComps || depth == maxDepths[pdfGouraudTriangleShading-1]) {
1956
 
    state->setFillColor(color0);
1957
 
    state->moveTo(x0, y0);
1958
 
    state->lineTo(x1, y1);
1959
 
    state->lineTo(x2, y2);
1960
 
    state->closePath();
1961
 
    builder->addPath(state, true, false);
1962
 
    state->clearPath();
1963
 
  } else {
1964
 
    x01 = 0.5 * (x0 + x1);
1965
 
    y01 = 0.5 * (y0 + y1);
1966
 
    x12 = 0.5 * (x1 + x2);
1967
 
    y12 = 0.5 * (y1 + y2);
1968
 
    x20 = 0.5 * (x2 + x0);
1969
 
    y20 = 0.5 * (y2 + y0);
1970
 
    //~ if the shading has a Function, this should interpolate on the
1971
 
    //~ function parameter, not on the color components
1972
 
    for (i = 0; i < nComps; ++i) {
1973
 
      color01.c[i] = (color0->c[i] + color1->c[i]) / 2;
1974
 
      color12.c[i] = (color1->c[i] + color2->c[i]) / 2;
1975
 
      color20.c[i] = (color2->c[i] + color0->c[i]) / 2;
1976
 
    }
1977
 
    gouraudFillTriangle(x0, y0, color0, x01, y01, &color01,
1978
 
                        x20, y20, &color20, nComps, depth + 1);
1979
 
    gouraudFillTriangle(x01, y01, &color01, x1, y1, color1,
1980
 
                        x12, y12, &color12, nComps, depth + 1);
1981
 
    gouraudFillTriangle(x01, y01, &color01, x12, y12, &color12,
1982
 
                        x20, y20, &color20, nComps, depth + 1);
1983
 
    gouraudFillTriangle(x20, y20, &color20, x12, y12, &color12,
1984
 
                        x2, y2, color2, nComps, depth + 1);
1985
 
  }
1986
 
}
1987
 
 
1988
 
void PdfParser::doPatchMeshShFill(GfxPatchMeshShading *shading) {
1989
 
  int start, i;
1990
 
 
1991
 
  if (shading->getNPatches() > 128) {
1992
 
    start = 3;
1993
 
  } else if (shading->getNPatches() > 64) {
1994
 
    start = 2;
1995
 
  } else if (shading->getNPatches() > 16) {
1996
 
    start = 1;
1997
 
  } else {
1998
 
    start = 0;
1999
 
  }
2000
 
  for (i = 0; i < shading->getNPatches(); ++i) {
2001
 
    fillPatch(shading->getPatch(i), shading->getColorSpace()->getNComps(),
2002
 
              start);
2003
 
  }
2004
 
}
2005
 
 
2006
 
void PdfParser::fillPatch(GfxPatch *patch, int nComps, int depth) {
2007
 
  GfxPatch patch00, patch01, patch10, patch11;
2008
 
#ifdef POPPLER_NEW_GFXPATCH
2009
 
  GfxColor color;
2010
 
#endif
2011
 
  double xx[4][8], yy[4][8];
2012
 
  double xxm, yym;
2013
 
  double patchColorDelta = colorDeltas[pdfPatchMeshShading-1];
2014
 
  int i;
2015
 
 
2016
 
  for (i = 0; i < nComps; ++i) {
2017
 
    if (abs(patch->color[0][0].c[i] - patch->color[0][1].c[i])
2018
 
          > patchColorDelta ||
2019
 
        abs(patch->color[0][1].c[i] - patch->color[1][1].c[i])
2020
 
          > patchColorDelta ||
2021
 
        abs(patch->color[1][1].c[i] - patch->color[1][0].c[i])
2022
 
          > patchColorDelta ||
2023
 
        abs(patch->color[1][0].c[i] - patch->color[0][0].c[i])
2024
 
          > patchColorDelta) {
2025
 
      break;
2026
 
    }
2027
 
#ifdef POPPLER_NEW_GFXPATCH
2028
 
    color.c[i] = GfxColorComp(patch->color[0][0].c[i]);
2029
 
#endif
2030
 
  }
2031
 
  if (i == nComps || depth == maxDepths[pdfPatchMeshShading-1]) {
2032
 
#ifdef POPPLER_NEW_GFXPATCH
2033
 
    state->setFillColor(&color);
2034
 
#else
2035
 
    state->setFillColor(&patch->color[0][0]);
2036
 
#endif
2037
 
    state->moveTo(patch->x[0][0], patch->y[0][0]);
2038
 
    state->curveTo(patch->x[0][1], patch->y[0][1],
2039
 
                   patch->x[0][2], patch->y[0][2],
2040
 
                   patch->x[0][3], patch->y[0][3]);
2041
 
    state->curveTo(patch->x[1][3], patch->y[1][3],
2042
 
                   patch->x[2][3], patch->y[2][3],
2043
 
                   patch->x[3][3], patch->y[3][3]);
2044
 
    state->curveTo(patch->x[3][2], patch->y[3][2],
2045
 
                   patch->x[3][1], patch->y[3][1],
2046
 
                   patch->x[3][0], patch->y[3][0]);
2047
 
    state->curveTo(patch->x[2][0], patch->y[2][0],
2048
 
                   patch->x[1][0], patch->y[1][0],
2049
 
                   patch->x[0][0], patch->y[0][0]);
2050
 
    state->closePath();
2051
 
    builder->addPath(state, true, false);
2052
 
    state->clearPath();
2053
 
  } else {
2054
 
    for (i = 0; i < 4; ++i) {
2055
 
      xx[i][0] = patch->x[i][0];
2056
 
      yy[i][0] = patch->y[i][0];
2057
 
      xx[i][1] = 0.5 * (patch->x[i][0] + patch->x[i][1]);
2058
 
      yy[i][1] = 0.5 * (patch->y[i][0] + patch->y[i][1]);
2059
 
      xxm = 0.5 * (patch->x[i][1] + patch->x[i][2]);
2060
 
      yym = 0.5 * (patch->y[i][1] + patch->y[i][2]);
2061
 
      xx[i][6] = 0.5 * (patch->x[i][2] + patch->x[i][3]);
2062
 
      yy[i][6] = 0.5 * (patch->y[i][2] + patch->y[i][3]);
2063
 
      xx[i][2] = 0.5 * (xx[i][1] + xxm);
2064
 
      yy[i][2] = 0.5 * (yy[i][1] + yym);
2065
 
      xx[i][5] = 0.5 * (xxm + xx[i][6]);
2066
 
      yy[i][5] = 0.5 * (yym + yy[i][6]);
2067
 
      xx[i][3] = xx[i][4] = 0.5 * (xx[i][2] + xx[i][5]);
2068
 
      yy[i][3] = yy[i][4] = 0.5 * (yy[i][2] + yy[i][5]);
2069
 
      xx[i][7] = patch->x[i][3];
2070
 
      yy[i][7] = patch->y[i][3];
2071
 
    }
2072
 
    for (i = 0; i < 4; ++i) {
2073
 
      patch00.x[0][i] = xx[0][i];
2074
 
      patch00.y[0][i] = yy[0][i];
2075
 
      patch00.x[1][i] = 0.5 * (xx[0][i] + xx[1][i]);
2076
 
      patch00.y[1][i] = 0.5 * (yy[0][i] + yy[1][i]);
2077
 
      xxm = 0.5 * (xx[1][i] + xx[2][i]);
2078
 
      yym = 0.5 * (yy[1][i] + yy[2][i]);
2079
 
      patch10.x[2][i] = 0.5 * (xx[2][i] + xx[3][i]);
2080
 
      patch10.y[2][i] = 0.5 * (yy[2][i] + yy[3][i]);
2081
 
      patch00.x[2][i] = 0.5 * (patch00.x[1][i] + xxm);
2082
 
      patch00.y[2][i] = 0.5 * (patch00.y[1][i] + yym);
2083
 
      patch10.x[1][i] = 0.5 * (xxm + patch10.x[2][i]);
2084
 
      patch10.y[1][i] = 0.5 * (yym + patch10.y[2][i]);
2085
 
      patch00.x[3][i] = 0.5 * (patch00.x[2][i] + patch10.x[1][i]);
2086
 
      patch00.y[3][i] = 0.5 * (patch00.y[2][i] + patch10.y[1][i]);
2087
 
      patch10.x[0][i] = patch00.x[3][i];
2088
 
      patch10.y[0][i] = patch00.y[3][i];
2089
 
      patch10.x[3][i] = xx[3][i];
2090
 
      patch10.y[3][i] = yy[3][i];
2091
 
    }
2092
 
    for (i = 4; i < 8; ++i) {
2093
 
      patch01.x[0][i-4] = xx[0][i];
2094
 
      patch01.y[0][i-4] = yy[0][i];
2095
 
      patch01.x[1][i-4] = 0.5 * (xx[0][i] + xx[1][i]);
2096
 
      patch01.y[1][i-4] = 0.5 * (yy[0][i] + yy[1][i]);
2097
 
      xxm = 0.5 * (xx[1][i] + xx[2][i]);
2098
 
      yym = 0.5 * (yy[1][i] + yy[2][i]);
2099
 
      patch11.x[2][i-4] = 0.5 * (xx[2][i] + xx[3][i]);
2100
 
      patch11.y[2][i-4] = 0.5 * (yy[2][i] + yy[3][i]);
2101
 
      patch01.x[2][i-4] = 0.5 * (patch01.x[1][i-4] + xxm);
2102
 
      patch01.y[2][i-4] = 0.5 * (patch01.y[1][i-4] + yym);
2103
 
      patch11.x[1][i-4] = 0.5 * (xxm + patch11.x[2][i-4]);
2104
 
      patch11.y[1][i-4] = 0.5 * (yym + patch11.y[2][i-4]);
2105
 
      patch01.x[3][i-4] = 0.5 * (patch01.x[2][i-4] + patch11.x[1][i-4]);
2106
 
      patch01.y[3][i-4] = 0.5 * (patch01.y[2][i-4] + patch11.y[1][i-4]);
2107
 
      patch11.x[0][i-4] = patch01.x[3][i-4];
2108
 
      patch11.y[0][i-4] = patch01.y[3][i-4];
2109
 
      patch11.x[3][i-4] = xx[3][i];
2110
 
      patch11.y[3][i-4] = yy[3][i];
2111
 
    }
2112
 
    //~ if the shading has a Function, this should interpolate on the
2113
 
    //~ function parameter, not on the color components
2114
 
    for (i = 0; i < nComps; ++i) {
2115
 
      patch00.color[0][0].c[i] = patch->color[0][0].c[i];
2116
 
      patch00.color[0][1].c[i] = (patch->color[0][0].c[i] +
2117
 
                                  patch->color[0][1].c[i]) / 2;
2118
 
      patch01.color[0][0].c[i] = patch00.color[0][1].c[i];
2119
 
      patch01.color[0][1].c[i] = patch->color[0][1].c[i];
2120
 
      patch01.color[1][1].c[i] = (patch->color[0][1].c[i] +
2121
 
                                  patch->color[1][1].c[i]) / 2;
2122
 
      patch11.color[0][1].c[i] = patch01.color[1][1].c[i];
2123
 
      patch11.color[1][1].c[i] = patch->color[1][1].c[i];
2124
 
      patch11.color[1][0].c[i] = (patch->color[1][1].c[i] +
2125
 
                                  patch->color[1][0].c[i]) / 2;
2126
 
      patch10.color[1][1].c[i] = patch11.color[1][0].c[i];
2127
 
      patch10.color[1][0].c[i] = patch->color[1][0].c[i];
2128
 
      patch10.color[0][0].c[i] = (patch->color[1][0].c[i] +
2129
 
                                  patch->color[0][0].c[i]) / 2;
2130
 
      patch00.color[1][0].c[i] = patch10.color[0][0].c[i];
2131
 
      patch00.color[1][1].c[i] = (patch00.color[1][0].c[i] +
2132
 
                                  patch01.color[1][1].c[i]) / 2;
2133
 
      patch01.color[1][0].c[i] = patch00.color[1][1].c[i];
2134
 
      patch11.color[0][0].c[i] = patch00.color[1][1].c[i];
2135
 
      patch10.color[0][1].c[i] = patch00.color[1][1].c[i];
2136
 
    }
2137
 
    fillPatch(&patch00, nComps, depth + 1);
2138
 
    fillPatch(&patch10, nComps, depth + 1);
2139
 
    fillPatch(&patch01, nComps, depth + 1);
2140
 
    fillPatch(&patch11, nComps, depth + 1);
2141
 
  }
2142
 
}
2143
 
 
2144
 
void PdfParser::doEndPath() {
2145
 
  if (state->isCurPt() && clip != clipNone) {
2146
 
    state->clip();
2147
 
    if (clip == clipNormal) {
2148
 
      clipHistory->setClip(state->getPath(), clipNormal);
2149
 
      builder->clip(state);
2150
 
    } else {
2151
 
      clipHistory->setClip(state->getPath(), clipEO);
2152
 
      builder->clip(state, true);
2153
 
    }
2154
 
  }
2155
 
  clip = clipNone;
2156
 
  state->clearPath();
2157
 
}
2158
 
 
2159
 
//------------------------------------------------------------------------
2160
 
// path clipping operators
2161
 
//------------------------------------------------------------------------
2162
 
 
2163
 
void PdfParser::opClip(Object args[], int numArgs) {
2164
 
  clip = clipNormal;
2165
 
}
2166
 
 
2167
 
void PdfParser::opEOClip(Object args[], int numArgs) {
2168
 
  clip = clipEO;
2169
 
}
2170
 
 
2171
 
//------------------------------------------------------------------------
2172
 
// text object operators
2173
 
//------------------------------------------------------------------------
2174
 
 
2175
 
void PdfParser::opBeginText(Object args[], int numArgs) {
2176
 
  state->setTextMat(1, 0, 0, 1, 0, 0);
2177
 
  state->textMoveTo(0, 0);
2178
 
  builder->updateTextPosition(0.0, 0.0);
2179
 
  fontChanged = gTrue;
2180
 
  builder->beginTextObject(state);
2181
 
}
2182
 
 
2183
 
void PdfParser::opEndText(Object args[], int numArgs) {
2184
 
  builder->endTextObject(state);
2185
 
}
2186
 
 
2187
 
//------------------------------------------------------------------------
2188
 
// text state operators
2189
 
//------------------------------------------------------------------------
2190
 
 
2191
 
void PdfParser::opSetCharSpacing(Object args[], int numArgs) {
2192
 
  state->setCharSpace(args[0].getNum());
2193
 
}
2194
 
 
2195
 
void PdfParser::opSetFont(Object args[], int numArgs) {
2196
 
  GfxFont *font;
2197
 
 
2198
 
  if (!(font = res->lookupFont(args[0].getName()))) {
2199
 
    // unsetting the font (drawing no text) is better than using the
2200
 
    // previous one and drawing random glyphs from it
2201
 
    state->setFont(NULL, args[1].getNum());
2202
 
    fontChanged = gTrue;
2203
 
    return;
2204
 
  }
2205
 
  if (printCommands) {
2206
 
    printf("  font: tag=%s name='%s' %g\n",
2207
 
           font->getTag()->getCString(),
2208
 
           font->getName() ? font->getName()->getCString() : "???",
2209
 
           args[1].getNum());
2210
 
    fflush(stdout);
2211
 
  }
2212
 
 
2213
 
  font->incRefCnt();
2214
 
  state->setFont(font, args[1].getNum());
2215
 
  fontChanged = gTrue;
2216
 
}
2217
 
 
2218
 
void PdfParser::opSetTextLeading(Object args[], int numArgs) {
2219
 
  state->setLeading(args[0].getNum());
2220
 
}
2221
 
 
2222
 
void PdfParser::opSetTextRender(Object args[], int numArgs) {
2223
 
  state->setRender(args[0].getInt());
2224
 
  builder->updateStyle(state);
2225
 
}
2226
 
 
2227
 
void PdfParser::opSetTextRise(Object args[], int numArgs) {
2228
 
  state->setRise(args[0].getNum());
2229
 
}
2230
 
 
2231
 
void PdfParser::opSetWordSpacing(Object args[], int numArgs) {
2232
 
  state->setWordSpace(args[0].getNum());
2233
 
}
2234
 
 
2235
 
void PdfParser::opSetHorizScaling(Object args[], int numArgs) {
2236
 
  state->setHorizScaling(args[0].getNum());
2237
 
  builder->updateTextMatrix(state);
2238
 
  fontChanged = gTrue;
2239
 
}
2240
 
 
2241
 
//------------------------------------------------------------------------
2242
 
// text positioning operators
2243
 
//------------------------------------------------------------------------
2244
 
 
2245
 
void PdfParser::opTextMove(Object args[], int numArgs) {
2246
 
  double tx, ty;
2247
 
 
2248
 
  tx = state->getLineX() + args[0].getNum();
2249
 
  ty = state->getLineY() + args[1].getNum();
2250
 
  state->textMoveTo(tx, ty);
2251
 
  builder->updateTextPosition(tx, ty);
2252
 
}
2253
 
 
2254
 
void PdfParser::opTextMoveSet(Object args[], int numArgs) {
2255
 
  double tx, ty;
2256
 
 
2257
 
  tx = state->getLineX() + args[0].getNum();
2258
 
  ty = args[1].getNum();
2259
 
  state->setLeading(-ty);
2260
 
  ty += state->getLineY();
2261
 
  state->textMoveTo(tx, ty);
2262
 
  builder->updateTextPosition(tx, ty);
2263
 
}
2264
 
 
2265
 
void PdfParser::opSetTextMatrix(Object args[], int numArgs) {
2266
 
  state->setTextMat(args[0].getNum(), args[1].getNum(),
2267
 
                    args[2].getNum(), args[3].getNum(),
2268
 
                    args[4].getNum(), args[5].getNum());
2269
 
  state->textMoveTo(0, 0);
2270
 
  builder->updateTextMatrix(state);
2271
 
  builder->updateTextPosition(0.0, 0.0);
2272
 
  fontChanged = gTrue;
2273
 
}
2274
 
 
2275
 
void PdfParser::opTextNextLine(Object args[], int numArgs) {
2276
 
  double tx, ty;
2277
 
 
2278
 
  tx = state->getLineX();
2279
 
  ty = state->getLineY() - state->getLeading();
2280
 
  state->textMoveTo(tx, ty);
2281
 
  builder->updateTextPosition(tx, ty);
2282
 
}
2283
 
 
2284
 
//------------------------------------------------------------------------
2285
 
// text string operators
2286
 
//------------------------------------------------------------------------
2287
 
 
2288
 
void PdfParser::opShowText(Object args[], int numArgs) {
2289
 
  if (!state->getFont()) {
2290
 
#ifdef POPPLER_NEW_ERRORAPI
2291
 
    error(errSyntaxError, getPos(), "No font in show");
2292
 
#else
2293
 
    error(getPos(), const_cast<char*>("No font in show"));
2294
 
#endif
2295
 
    return;
2296
 
  }
2297
 
  if (fontChanged) {
2298
 
    builder->updateFont(state);
2299
 
    fontChanged = gFalse;
2300
 
  }
2301
 
  doShowText(args[0].getString());
2302
 
}
2303
 
 
2304
 
void PdfParser::opMoveShowText(Object args[], int numArgs) {
2305
 
  double tx, ty;
2306
 
 
2307
 
  if (!state->getFont()) {
2308
 
#ifdef POPPLER_NEW_ERRORAPI
2309
 
    error(errSyntaxError, getPos(), "No font in move/show");
2310
 
#else
2311
 
    error(getPos(), const_cast<char*>("No font in move/show"));
2312
 
#endif
2313
 
    return;
2314
 
  }
2315
 
  if (fontChanged) {
2316
 
    builder->updateFont(state);
2317
 
    fontChanged = gFalse;
2318
 
  }
2319
 
  tx = state->getLineX();
2320
 
  ty = state->getLineY() - state->getLeading();
2321
 
  state->textMoveTo(tx, ty);
2322
 
  builder->updateTextPosition(tx, ty);
2323
 
  doShowText(args[0].getString());
2324
 
}
2325
 
 
2326
 
void PdfParser::opMoveSetShowText(Object args[], int numArgs) {
2327
 
  double tx, ty;
2328
 
 
2329
 
  if (!state->getFont()) {
2330
 
#ifdef POPPLER_NEW_ERRORAPI
2331
 
    error(errSyntaxError, getPos(), "No font in move/set/show");
2332
 
#else
2333
 
    error(getPos(), const_cast<char*>("No font in move/set/show"));
2334
 
#endif
2335
 
    return;
2336
 
  }
2337
 
  if (fontChanged) {
2338
 
    builder->updateFont(state);
2339
 
    fontChanged = gFalse;
2340
 
  }
2341
 
  state->setWordSpace(args[0].getNum());
2342
 
  state->setCharSpace(args[1].getNum());
2343
 
  tx = state->getLineX();
2344
 
  ty = state->getLineY() - state->getLeading();
2345
 
  state->textMoveTo(tx, ty);
2346
 
  builder->updateTextPosition(tx, ty);
2347
 
  doShowText(args[2].getString());
2348
 
}
2349
 
 
2350
 
void PdfParser::opShowSpaceText(Object args[], int numArgs) {
2351
 
  Array *a;
2352
 
  Object obj;
2353
 
  int wMode;
2354
 
  int i;
2355
 
 
2356
 
  if (!state->getFont()) {
2357
 
#ifdef POPPLER_NEW_ERRORAPI
2358
 
    error(errSyntaxError, getPos(), "No font in show/space");
2359
 
#else
2360
 
    error(getPos(), const_cast<char*>("No font in show/space"));
2361
 
#endif
2362
 
    return;
2363
 
  }
2364
 
  if (fontChanged) {
2365
 
    builder->updateFont(state);
2366
 
    fontChanged = gFalse;
2367
 
  }
2368
 
  wMode = state->getFont()->getWMode();
2369
 
  a = args[0].getArray();
2370
 
  for (i = 0; i < a->getLength(); ++i) {
2371
 
    a->get(i, &obj);
2372
 
    if (obj.isNum()) {
2373
 
      // this uses the absolute value of the font size to match
2374
 
      // Acrobat's behavior
2375
 
      if (wMode) {
2376
 
        state->textShift(0, -obj.getNum() * 0.001 *
2377
 
                            fabs(state->getFontSize()));
2378
 
      } else {
2379
 
        state->textShift(-obj.getNum() * 0.001 *
2380
 
                         fabs(state->getFontSize()), 0);
2381
 
      }
2382
 
      builder->updateTextShift(state, obj.getNum());
2383
 
    } else if (obj.isString()) {
2384
 
      doShowText(obj.getString());
2385
 
    } else {
2386
 
#ifdef POPPLER_NEW_ERRORAPI
2387
 
      error(errSyntaxError, getPos(), "Element of show/space array must be number or string");
2388
 
#else
2389
 
      error(getPos(), const_cast<char*>("Element of show/space array must be number or string"));
2390
 
#endif
2391
 
    }
2392
 
    obj.free();
2393
 
  }
2394
 
}
2395
 
 
2396
 
 
2397
 
 
2398
 
/*
2399
 
 * The `POPPLER_NEW_GFXFONT' stuff is for the change to GfxFont's getNextChar() call.
2400
 
 * Thanks to tsdgeos for the fix.
2401
 
 * Miklos, does this look ok?
2402
 
 */   
2403
 
 
2404
 
void PdfParser::doShowText(GooString *s) {
2405
 
  GfxFont *font;
2406
 
  int wMode;
2407
 
  double riseX, riseY;
2408
 
  CharCode code;
2409
 
#ifdef POPPLER_NEW_GFXFONT
2410
 
  Unicode *u = NULL;
2411
 
#else
2412
 
  Unicode u[8];
2413
 
#endif
2414
 
  double x, y, dx, dy, curX, curY, tdx, tdy, lineX, lineY;
2415
 
  double originX, originY, tOriginX, tOriginY;
2416
 
  double oldCTM[6], newCTM[6];
2417
 
  double *mat;
2418
 
  Object charProc;
2419
 
  Dict *resDict;
2420
 
  Parser *oldParser;
2421
 
  char *p;
2422
 
  int len, n, uLen, i;
2423
 
 
2424
 
  font = state->getFont();
2425
 
  wMode = font->getWMode();
2426
 
 
2427
 
  builder->beginString(state, s);
2428
 
 
2429
 
  // handle a Type 3 char
2430
 
  if (font->getType() == fontType3 && 0) {//out->interpretType3Chars()) {
2431
 
    mat = state->getCTM();
2432
 
    for (i = 0; i < 6; ++i) {
2433
 
      oldCTM[i] = mat[i];
2434
 
    }
2435
 
    mat = state->getTextMat();
2436
 
    newCTM[0] = mat[0] * oldCTM[0] + mat[1] * oldCTM[2];
2437
 
    newCTM[1] = mat[0] * oldCTM[1] + mat[1] * oldCTM[3];
2438
 
    newCTM[2] = mat[2] * oldCTM[0] + mat[3] * oldCTM[2];
2439
 
    newCTM[3] = mat[2] * oldCTM[1] + mat[3] * oldCTM[3];
2440
 
    mat = font->getFontMatrix();
2441
 
    newCTM[0] = mat[0] * newCTM[0] + mat[1] * newCTM[2];
2442
 
    newCTM[1] = mat[0] * newCTM[1] + mat[1] * newCTM[3];
2443
 
    newCTM[2] = mat[2] * newCTM[0] + mat[3] * newCTM[2];
2444
 
    newCTM[3] = mat[2] * newCTM[1] + mat[3] * newCTM[3];
2445
 
    newCTM[0] *= state->getFontSize();
2446
 
    newCTM[1] *= state->getFontSize();
2447
 
    newCTM[2] *= state->getFontSize();
2448
 
    newCTM[3] *= state->getFontSize();
2449
 
    newCTM[0] *= state->getHorizScaling();
2450
 
    newCTM[2] *= state->getHorizScaling();
2451
 
    state->textTransformDelta(0, state->getRise(), &riseX, &riseY);
2452
 
    curX = state->getCurX();
2453
 
    curY = state->getCurY();
2454
 
    lineX = state->getLineX();
2455
 
    lineY = state->getLineY();
2456
 
    oldParser = parser;
2457
 
    p = s->getCString();
2458
 
    len = s->getLength();
2459
 
    while (len > 0) {
2460
 
      n = font->getNextChar(p, len, &code,
2461
 
#ifdef POPPLER_NEW_GFXFONT
2462
 
                            &u, &uLen,  /* TODO: This looks like a memory leak for u. */
2463
 
#else
2464
 
                            u, (int)(sizeof(u) / sizeof(Unicode)), &uLen,
2465
 
#endif
2466
 
                            &dx, &dy, &originX, &originY);
2467
 
      dx = dx * state->getFontSize() + state->getCharSpace();
2468
 
      if (n == 1 && *p == ' ') {
2469
 
        dx += state->getWordSpace();
2470
 
      }
2471
 
      dx *= state->getHorizScaling();
2472
 
      dy *= state->getFontSize();
2473
 
      state->textTransformDelta(dx, dy, &tdx, &tdy);
2474
 
      state->transform(curX + riseX, curY + riseY, &x, &y);
2475
 
      saveState();
2476
 
      state->setCTM(newCTM[0], newCTM[1], newCTM[2], newCTM[3], x, y);
2477
 
      //~ the CTM concat values here are wrong (but never used)
2478
 
      //out->updateCTM(state, 1, 0, 0, 1, 0, 0);
2479
 
      if (0){ /*!out->beginType3Char(state, curX + riseX, curY + riseY, tdx, tdy,
2480
 
                               code, u, uLen)) {*/
2481
 
        ((Gfx8BitFont *)font)->getCharProc(code, &charProc);
2482
 
        if ((resDict = ((Gfx8BitFont *)font)->getResources())) {
2483
 
          pushResources(resDict);
2484
 
        }
2485
 
        if (charProc.isStream()) {
2486
 
          //parse(&charProc, gFalse); // TODO: parse into SVG font
2487
 
        } else {
2488
 
#ifdef POPPLER_NEW_ERRORAPI
2489
 
          error(errSyntaxError, getPos(), "Missing or bad Type3 CharProc entry");
2490
 
#else
2491
 
          error(getPos(), const_cast<char*>("Missing or bad Type3 CharProc entry"));
2492
 
#endif
2493
 
        }
2494
 
        //out->endType3Char(state);
2495
 
        if (resDict) {
2496
 
          popResources();
2497
 
        }
2498
 
        charProc.free();
2499
 
      }
2500
 
      restoreState();
2501
 
      // GfxState::restore() does *not* restore the current position,
2502
 
      // so we deal with it here using (curX, curY) and (lineX, lineY)
2503
 
      curX += tdx;
2504
 
      curY += tdy;
2505
 
      state->moveTo(curX, curY);
2506
 
      state->textSetPos(lineX, lineY);
2507
 
      p += n;
2508
 
      len -= n;
2509
 
    }
2510
 
    parser = oldParser;
2511
 
 
2512
 
  } else {
2513
 
    state->textTransformDelta(0, state->getRise(), &riseX, &riseY);
2514
 
    p = s->getCString();
2515
 
    len = s->getLength();
2516
 
    while (len > 0) {
2517
 
      n = font->getNextChar(p, len, &code,
2518
 
#ifdef POPPLER_NEW_GFXFONT
2519
 
                            &u, &uLen,  /* TODO: This looks like a memory leak for u. */
2520
 
#else
2521
 
                            u, (int)(sizeof(u) / sizeof(Unicode)), &uLen,
2522
 
#endif
2523
 
                            &dx, &dy, &originX, &originY);
2524
 
      
2525
 
      if (wMode) {
2526
 
        dx *= state->getFontSize();
2527
 
        dy = dy * state->getFontSize() + state->getCharSpace();
2528
 
        if (n == 1 && *p == ' ') {
2529
 
          dy += state->getWordSpace();
2530
 
        }
2531
 
      } else {
2532
 
        dx = dx * state->getFontSize() + state->getCharSpace();
2533
 
        if (n == 1 && *p == ' ') {
2534
 
          dx += state->getWordSpace();
2535
 
        }
2536
 
        dx *= state->getHorizScaling();
2537
 
        dy *= state->getFontSize();
2538
 
      }
2539
 
      state->textTransformDelta(dx, dy, &tdx, &tdy);
2540
 
      originX *= state->getFontSize();
2541
 
      originY *= state->getFontSize();
2542
 
      state->textTransformDelta(originX, originY, &tOriginX, &tOriginY);
2543
 
      builder->addChar(state, state->getCurX() + riseX, state->getCurY() + riseY,
2544
 
                       dx, dy, tOriginX, tOriginY, code, n, u, uLen);
2545
 
      state->shift(tdx, tdy);
2546
 
      p += n;
2547
 
      len -= n;
2548
 
    }
2549
 
  }
2550
 
 
2551
 
  builder->endString(state);
2552
 
}
2553
 
 
2554
 
 
2555
 
//------------------------------------------------------------------------
2556
 
// XObject operators
2557
 
//------------------------------------------------------------------------
2558
 
 
2559
 
void PdfParser::opXObject(Object args[], int numArgs) {
2560
 
  char *name;
2561
 
  Object obj1, obj2, obj3, refObj;
2562
 
 
2563
 
  name = args[0].getName();
2564
 
  if (!res->lookupXObject(name, &obj1)) {
2565
 
    return;
2566
 
  }
2567
 
  if (!obj1.isStream()) {
2568
 
#ifdef POPPLER_NEW_ERRORAPI
2569
 
    error(errSyntaxError, getPos(), "XObject '{0:s}' is wrong type", name);
2570
 
#else
2571
 
    error(getPos(), const_cast<char*>("XObject '%s' is wrong type"), name);
2572
 
#endif
2573
 
    obj1.free();
2574
 
    return;
2575
 
  }
2576
 
  obj1.streamGetDict()->lookup(const_cast<char*>("Subtype"), &obj2);
2577
 
  if (obj2.isName(const_cast<char*>("Image"))) {
2578
 
    res->lookupXObjectNF(name, &refObj);
2579
 
    doImage(&refObj, obj1.getStream(), gFalse);
2580
 
    refObj.free();
2581
 
  } else if (obj2.isName(const_cast<char*>("Form"))) {
2582
 
    doForm(&obj1);
2583
 
  } else if (obj2.isName(const_cast<char*>("PS"))) {
2584
 
    obj1.streamGetDict()->lookup(const_cast<char*>("Level1"), &obj3);
2585
 
/*    out->psXObject(obj1.getStream(),
2586
 
                   obj3.isStream() ? obj3.getStream() : (Stream *)NULL);*/
2587
 
  } else if (obj2.isName()) {
2588
 
#ifdef POPPLER_NEW_ERRORAPI
2589
 
    error(errSyntaxError, getPos(), "Unknown XObject subtype '{0:s}'", obj2.getName());
2590
 
#else
2591
 
    error(getPos(), const_cast<char*>("Unknown XObject subtype '%s'"), obj2.getName());
2592
 
#endif
2593
 
  } else {
2594
 
#ifdef POPPLER_NEW_ERRORAPI
2595
 
    error(errSyntaxError, getPos(), "XObject subtype is missing or wrong type");
2596
 
#else
2597
 
    error(getPos(), const_cast<char*>("XObject subtype is missing or wrong type"));
2598
 
#endif
2599
 
  }
2600
 
  obj2.free();
2601
 
  obj1.free();
2602
 
}
2603
 
 
2604
 
void PdfParser::doImage(Object *ref, Stream *str, GBool inlineImg) {
2605
 
  Dict *dict, *maskDict;
2606
 
  int width, height;
2607
 
  int bits, maskBits;
2608
 
  StreamColorSpaceMode csMode;
2609
 
  GBool mask;
2610
 
  GBool invert;
2611
 
  GfxColorSpace *colorSpace, *maskColorSpace;
2612
 
  GfxImageColorMap *colorMap, *maskColorMap;
2613
 
  Object maskObj, smaskObj;
2614
 
  GBool haveColorKeyMask, haveExplicitMask, haveSoftMask;
2615
 
  int maskColors[2*gfxColorMaxComps];
2616
 
  int maskWidth, maskHeight;
2617
 
  GBool maskInvert;
2618
 
  Stream *maskStr;
2619
 
  Object obj1, obj2;
2620
 
  int i;
2621
 
 
2622
 
  // get info from the stream
2623
 
  bits = 0;
2624
 
  csMode = streamCSNone;
2625
 
  str->getImageParams(&bits, &csMode);
2626
 
 
2627
 
  // get stream dict
2628
 
  dict = str->getDict();
2629
 
 
2630
 
  // get size
2631
 
  dict->lookup(const_cast<char*>("Width"), &obj1);
2632
 
  if (obj1.isNull()) {
2633
 
    obj1.free();
2634
 
    dict->lookup(const_cast<char*>("W"), &obj1);
2635
 
  }
2636
 
  if (obj1.isInt())
2637
 
    width = obj1.getInt();
2638
 
  else if (obj1.isReal())
2639
 
    width = (int)obj1.getReal();
2640
 
  else
2641
 
    goto err2;
2642
 
  obj1.free();
2643
 
  dict->lookup(const_cast<char*>("Height"), &obj1);
2644
 
  if (obj1.isNull()) {
2645
 
    obj1.free();
2646
 
    dict->lookup(const_cast<char*>("H"), &obj1);
2647
 
  }
2648
 
  if (obj1.isInt())
2649
 
    height = obj1.getInt();
2650
 
  else if (obj1.isReal())
2651
 
    height = (int)obj1.getReal();
2652
 
  else
2653
 
    goto err2;
2654
 
  obj1.free();
2655
 
 
2656
 
  // image or mask?
2657
 
  dict->lookup(const_cast<char*>("ImageMask"), &obj1);
2658
 
  if (obj1.isNull()) {
2659
 
    obj1.free();
2660
 
    dict->lookup(const_cast<char*>("IM"), &obj1);
2661
 
  }
2662
 
  mask = gFalse;
2663
 
  if (obj1.isBool())
2664
 
    mask = obj1.getBool();
2665
 
  else if (!obj1.isNull())
2666
 
    goto err2;
2667
 
  obj1.free();
2668
 
 
2669
 
  // bit depth
2670
 
  if (bits == 0) {
2671
 
    dict->lookup(const_cast<char*>("BitsPerComponent"), &obj1);
2672
 
    if (obj1.isNull()) {
2673
 
      obj1.free();
2674
 
      dict->lookup(const_cast<char*>("BPC"), &obj1);
2675
 
    }
2676
 
    if (obj1.isInt()) {
2677
 
      bits = obj1.getInt();
2678
 
    } else if (mask) {
2679
 
      bits = 1;
2680
 
    } else {
2681
 
      goto err2;
2682
 
    }
2683
 
    obj1.free();
2684
 
  }
2685
 
 
2686
 
  // display a mask
2687
 
  if (mask) {
2688
 
 
2689
 
    // check for inverted mask
2690
 
    if (bits != 1)
2691
 
      goto err1;
2692
 
    invert = gFalse;
2693
 
    dict->lookup(const_cast<char*>("Decode"), &obj1);
2694
 
    if (obj1.isNull()) {
2695
 
      obj1.free();
2696
 
      dict->lookup(const_cast<char*>("D"), &obj1);
2697
 
    }
2698
 
    if (obj1.isArray()) {
2699
 
      obj1.arrayGet(0, &obj2);
2700
 
      if (obj2.isInt() && obj2.getInt() == 1)
2701
 
        invert = gTrue;
2702
 
      obj2.free();
2703
 
    } else if (!obj1.isNull()) {
2704
 
      goto err2;
2705
 
    }
2706
 
    obj1.free();
2707
 
 
2708
 
    // draw it
2709
 
    builder->addImageMask(state, str, width, height, invert);
2710
 
 
2711
 
  } else {
2712
 
 
2713
 
    // get color space and color map
2714
 
    dict->lookup(const_cast<char*>("ColorSpace"), &obj1);
2715
 
    if (obj1.isNull()) {
2716
 
      obj1.free();
2717
 
      dict->lookup(const_cast<char*>("CS"), &obj1);
2718
 
    }
2719
 
    if (obj1.isName()) {
2720
 
      res->lookupColorSpace(obj1.getName(), &obj2);
2721
 
      if (!obj2.isNull()) {
2722
 
        obj1.free();
2723
 
        obj1 = obj2;
2724
 
      } else {
2725
 
        obj2.free();
2726
 
      }
2727
 
    }
2728
 
    if (!obj1.isNull()) {
2729
 
#if defined(POPPLER_NEW_COLOR_SPACE_API) || defined(POPPLER_NEW_ERRORAPI)
2730
 
      colorSpace = GfxColorSpace::parse(&obj1, NULL);
2731
 
#else
2732
 
      colorSpace = GfxColorSpace::parse(&obj1);
2733
 
#endif
2734
 
    } else if (csMode == streamCSDeviceGray) {
2735
 
      colorSpace = new GfxDeviceGrayColorSpace();
2736
 
    } else if (csMode == streamCSDeviceRGB) {
2737
 
      colorSpace = new GfxDeviceRGBColorSpace();
2738
 
    } else if (csMode == streamCSDeviceCMYK) {
2739
 
      colorSpace = new GfxDeviceCMYKColorSpace();
2740
 
    } else {
2741
 
      colorSpace = NULL;
2742
 
    }
2743
 
    obj1.free();
2744
 
    if (!colorSpace) {
2745
 
      goto err1;
2746
 
    }
2747
 
    dict->lookup(const_cast<char*>("Decode"), &obj1);
2748
 
    if (obj1.isNull()) {
2749
 
      obj1.free();
2750
 
      dict->lookup(const_cast<char*>("D"), &obj1);
2751
 
    }
2752
 
    colorMap = new GfxImageColorMap(bits, &obj1, colorSpace);
2753
 
    obj1.free();
2754
 
    if (!colorMap->isOk()) {
2755
 
      delete colorMap;
2756
 
      goto err1;
2757
 
    }
2758
 
 
2759
 
    // get the mask
2760
 
    haveColorKeyMask = haveExplicitMask = haveSoftMask = gFalse;
2761
 
    maskStr = NULL; // make gcc happy
2762
 
    maskWidth = maskHeight = 0; // make gcc happy
2763
 
    maskInvert = gFalse; // make gcc happy
2764
 
    maskColorMap = NULL; // make gcc happy
2765
 
    dict->lookup(const_cast<char*>("Mask"), &maskObj);
2766
 
    dict->lookup(const_cast<char*>("SMask"), &smaskObj);
2767
 
    if (smaskObj.isStream()) {
2768
 
      // soft mask
2769
 
      if (inlineImg) {
2770
 
        goto err1;
2771
 
      }
2772
 
      maskStr = smaskObj.getStream();
2773
 
      maskDict = smaskObj.streamGetDict();
2774
 
      maskDict->lookup(const_cast<char*>("Width"), &obj1);
2775
 
      if (obj1.isNull()) {
2776
 
        obj1.free();
2777
 
        maskDict->lookup(const_cast<char*>("W"), &obj1);
2778
 
      }
2779
 
      if (!obj1.isInt()) {
2780
 
        goto err2;
2781
 
      }
2782
 
      maskWidth = obj1.getInt();
2783
 
      obj1.free();
2784
 
      maskDict->lookup(const_cast<char*>("Height"), &obj1);
2785
 
      if (obj1.isNull()) {
2786
 
        obj1.free();
2787
 
        maskDict->lookup(const_cast<char*>("H"), &obj1);
2788
 
      }
2789
 
      if (!obj1.isInt()) {
2790
 
        goto err2;
2791
 
      }
2792
 
      maskHeight = obj1.getInt();
2793
 
      obj1.free();
2794
 
      maskDict->lookup(const_cast<char*>("BitsPerComponent"), &obj1);
2795
 
      if (obj1.isNull()) {
2796
 
        obj1.free();
2797
 
        maskDict->lookup(const_cast<char*>("BPC"), &obj1);
2798
 
      }
2799
 
      if (!obj1.isInt()) {
2800
 
        goto err2;
2801
 
      }
2802
 
      maskBits = obj1.getInt();
2803
 
      obj1.free();
2804
 
      maskDict->lookup(const_cast<char*>("ColorSpace"), &obj1);
2805
 
      if (obj1.isNull()) {
2806
 
        obj1.free();
2807
 
        maskDict->lookup(const_cast<char*>("CS"), &obj1);
2808
 
      }
2809
 
      if (obj1.isName()) {
2810
 
        res->lookupColorSpace(obj1.getName(), &obj2);
2811
 
        if (!obj2.isNull()) {
2812
 
          obj1.free();
2813
 
          obj1 = obj2;
2814
 
        } else {
2815
 
          obj2.free();
2816
 
        }
2817
 
      }
2818
 
#if defined(POPPLER_NEW_COLOR_SPACE_API) || defined(POPPLER_NEW_ERRORAPI)
2819
 
      maskColorSpace = GfxColorSpace::parse(&obj1, NULL);
2820
 
#else
2821
 
      maskColorSpace = GfxColorSpace::parse(&obj1);
2822
 
#endif
2823
 
      obj1.free();
2824
 
      if (!maskColorSpace || maskColorSpace->getMode() != csDeviceGray) {
2825
 
        goto err1;
2826
 
      }
2827
 
      maskDict->lookup(const_cast<char*>("Decode"), &obj1);
2828
 
      if (obj1.isNull()) {
2829
 
        obj1.free();
2830
 
        maskDict->lookup(const_cast<char*>("D"), &obj1);
2831
 
      }
2832
 
      maskColorMap = new GfxImageColorMap(maskBits, &obj1, maskColorSpace);
2833
 
      obj1.free();
2834
 
      if (!maskColorMap->isOk()) {
2835
 
        delete maskColorMap;
2836
 
        goto err1;
2837
 
      }
2838
 
      //~ handle the Matte entry
2839
 
      haveSoftMask = gTrue;
2840
 
    } else if (maskObj.isArray()) {
2841
 
      // color key mask
2842
 
      for (i = 0;
2843
 
           i < maskObj.arrayGetLength() && i < 2*gfxColorMaxComps;
2844
 
           ++i) {
2845
 
        maskObj.arrayGet(i, &obj1);
2846
 
        maskColors[i] = obj1.getInt();
2847
 
        obj1.free();
2848
 
      }
2849
 
      haveColorKeyMask = gTrue;
2850
 
    } else if (maskObj.isStream()) {
2851
 
      // explicit mask
2852
 
      if (inlineImg) {
2853
 
        goto err1;
2854
 
      }
2855
 
      maskStr = maskObj.getStream();
2856
 
      maskDict = maskObj.streamGetDict();
2857
 
      maskDict->lookup(const_cast<char*>("Width"), &obj1);
2858
 
      if (obj1.isNull()) {
2859
 
        obj1.free();
2860
 
        maskDict->lookup(const_cast<char*>("W"), &obj1);
2861
 
      }
2862
 
      if (!obj1.isInt()) {
2863
 
        goto err2;
2864
 
      }
2865
 
      maskWidth = obj1.getInt();
2866
 
      obj1.free();
2867
 
      maskDict->lookup(const_cast<char*>("Height"), &obj1);
2868
 
      if (obj1.isNull()) {
2869
 
        obj1.free();
2870
 
        maskDict->lookup(const_cast<char*>("H"), &obj1);
2871
 
      }
2872
 
      if (!obj1.isInt()) {
2873
 
        goto err2;
2874
 
      }
2875
 
      maskHeight = obj1.getInt();
2876
 
      obj1.free();
2877
 
      maskDict->lookup(const_cast<char*>("ImageMask"), &obj1);
2878
 
      if (obj1.isNull()) {
2879
 
        obj1.free();
2880
 
        maskDict->lookup(const_cast<char*>("IM"), &obj1);
2881
 
      }
2882
 
      if (!obj1.isBool() || !obj1.getBool()) {
2883
 
        goto err2;
2884
 
      }
2885
 
      obj1.free();
2886
 
      maskInvert = gFalse;
2887
 
      maskDict->lookup(const_cast<char*>("Decode"), &obj1);
2888
 
      if (obj1.isNull()) {
2889
 
        obj1.free();
2890
 
        maskDict->lookup(const_cast<char*>("D"), &obj1);
2891
 
      }
2892
 
      if (obj1.isArray()) {
2893
 
        obj1.arrayGet(0, &obj2);
2894
 
        if (obj2.isInt() && obj2.getInt() == 1) {
2895
 
          maskInvert = gTrue;
2896
 
        }
2897
 
        obj2.free();
2898
 
      } else if (!obj1.isNull()) {
2899
 
        goto err2;
2900
 
      }
2901
 
      obj1.free();
2902
 
      haveExplicitMask = gTrue;
2903
 
    }
2904
 
 
2905
 
    // draw it
2906
 
    if (haveSoftMask) {
2907
 
        builder->addSoftMaskedImage(state, str, width, height, colorMap,
2908
 
                                    maskStr, maskWidth, maskHeight, maskColorMap);
2909
 
      delete maskColorMap;
2910
 
    } else if (haveExplicitMask) {
2911
 
        builder->addMaskedImage(state, str, width, height, colorMap,
2912
 
                                maskStr, maskWidth, maskHeight, maskInvert);
2913
 
    } else {
2914
 
      builder->addImage(state, str, width, height, colorMap,
2915
 
                        haveColorKeyMask ? maskColors : (int *)NULL);
2916
 
    }
2917
 
    delete colorMap;
2918
 
 
2919
 
    maskObj.free();
2920
 
    smaskObj.free();
2921
 
  }
2922
 
 
2923
 
  return;
2924
 
 
2925
 
 err2:
2926
 
  obj1.free();
2927
 
 err1:
2928
 
#ifdef POPPLER_NEW_ERRORAPI
2929
 
  error(errSyntaxError, getPos(), "Bad image parameters");
2930
 
#else
2931
 
  error(getPos(), const_cast<char*>("Bad image parameters"));
2932
 
#endif
2933
 
}
2934
 
 
2935
 
void PdfParser::doForm(Object *str) {
2936
 
  Dict *dict;
2937
 
  GBool transpGroup, isolated, knockout;
2938
 
  GfxColorSpace *blendingColorSpace;
2939
 
  Object matrixObj, bboxObj;
2940
 
  double m[6], bbox[4];
2941
 
  Object resObj;
2942
 
  Dict *resDict;
2943
 
  Object obj1, obj2, obj3;
2944
 
  int i;
2945
 
 
2946
 
  // check for excessive recursion
2947
 
  if (formDepth > 20) {
2948
 
    return;
2949
 
  }
2950
 
 
2951
 
  // get stream dict
2952
 
  dict = str->streamGetDict();
2953
 
 
2954
 
  // check form type
2955
 
  dict->lookup(const_cast<char*>("FormType"), &obj1);
2956
 
  if (!(obj1.isNull() || (obj1.isInt() && obj1.getInt() == 1))) {
2957
 
#ifdef POPPLER_NEW_ERRORAPI
2958
 
    error(errSyntaxError, getPos(), "Unknown form type");
2959
 
#else
2960
 
    error(getPos(), const_cast<char*>("Unknown form type"));
2961
 
#endif
2962
 
  }
2963
 
  obj1.free();
2964
 
 
2965
 
  // get bounding box
2966
 
  dict->lookup(const_cast<char*>("BBox"), &bboxObj);
2967
 
  if (!bboxObj.isArray()) {
2968
 
    bboxObj.free();
2969
 
#ifdef POPPLER_NEW_ERRORAPI
2970
 
    error(errSyntaxError, getPos(), "Bad form bounding box");
2971
 
#else
2972
 
    error(getPos(), const_cast<char*>("Bad form bounding box"));
2973
 
#endif
2974
 
    return;
2975
 
  }
2976
 
  for (i = 0; i < 4; ++i) {
2977
 
    bboxObj.arrayGet(i, &obj1);
2978
 
    bbox[i] = obj1.getNum();
2979
 
    obj1.free();
2980
 
  }
2981
 
  bboxObj.free();
2982
 
 
2983
 
  // get matrix
2984
 
  dict->lookup(const_cast<char*>("Matrix"), &matrixObj);
2985
 
  if (matrixObj.isArray()) {
2986
 
    for (i = 0; i < 6; ++i) {
2987
 
      matrixObj.arrayGet(i, &obj1);
2988
 
      m[i] = obj1.getNum();
2989
 
      obj1.free();
2990
 
    }
2991
 
  } else {
2992
 
    m[0] = 1; m[1] = 0;
2993
 
    m[2] = 0; m[3] = 1;
2994
 
    m[4] = 0; m[5] = 0;
2995
 
  }
2996
 
  matrixObj.free();
2997
 
 
2998
 
  // get resources
2999
 
  dict->lookup(const_cast<char*>("Resources"), &resObj);
3000
 
  resDict = resObj.isDict() ? resObj.getDict() : (Dict *)NULL;
3001
 
 
3002
 
  // check for a transparency group
3003
 
  transpGroup = isolated = knockout = gFalse;
3004
 
  blendingColorSpace = NULL;
3005
 
  if (dict->lookup(const_cast<char*>("Group"), &obj1)->isDict()) {
3006
 
    if (obj1.dictLookup(const_cast<char*>("S"), &obj2)->isName(const_cast<char*>("Transparency"))) {
3007
 
      transpGroup = gTrue;
3008
 
      if (!obj1.dictLookup(const_cast<char*>("CS"), &obj3)->isNull()) {
3009
 
#if defined(POPPLER_NEW_COLOR_SPACE_API) || defined(POPPLER_NEW_ERRORAPI)
3010
 
        blendingColorSpace = GfxColorSpace::parse(&obj3, NULL);
3011
 
#else
3012
 
        blendingColorSpace = GfxColorSpace::parse(&obj3);
3013
 
#endif
3014
 
      }
3015
 
      obj3.free();
3016
 
      if (obj1.dictLookup(const_cast<char*>("I"), &obj3)->isBool()) {
3017
 
        isolated = obj3.getBool();
3018
 
      }
3019
 
      obj3.free();
3020
 
      if (obj1.dictLookup(const_cast<char*>("K"), &obj3)->isBool()) {
3021
 
        knockout = obj3.getBool();
3022
 
      }
3023
 
      obj3.free();
3024
 
    }
3025
 
    obj2.free();
3026
 
  }
3027
 
  obj1.free();
3028
 
 
3029
 
  // draw it
3030
 
  ++formDepth;
3031
 
  doForm1(str, resDict, m, bbox,
3032
 
          transpGroup, gFalse, blendingColorSpace, isolated, knockout);
3033
 
  --formDepth;
3034
 
 
3035
 
  if (blendingColorSpace) {
3036
 
    delete blendingColorSpace;
3037
 
  }
3038
 
  resObj.free();
3039
 
}
3040
 
 
3041
 
void PdfParser::doForm1(Object *str, Dict *resDict, double *matrix, double *bbox,
3042
 
                  GBool transpGroup, GBool softMask,
3043
 
                  GfxColorSpace *blendingColorSpace,
3044
 
                  GBool isolated, GBool knockout,
3045
 
                  GBool alpha, Function *transferFunc,
3046
 
                  GfxColor *backdropColor) {
3047
 
  Parser *oldParser;
3048
 
  double oldBaseMatrix[6];
3049
 
  int i;
3050
 
 
3051
 
  // push new resources on stack
3052
 
  pushResources(resDict);
3053
 
 
3054
 
  // save current graphics state
3055
 
  saveState();
3056
 
 
3057
 
  // kill any pre-existing path
3058
 
  state->clearPath();
3059
 
 
3060
 
  if (softMask || transpGroup) {
3061
 
    builder->clearSoftMask(state);
3062
 
    builder->pushTransparencyGroup(state, bbox, blendingColorSpace,
3063
 
                                   isolated, knockout, softMask);
3064
 
  }
3065
 
 
3066
 
  // save current parser
3067
 
  oldParser = parser;
3068
 
 
3069
 
  // set form transformation matrix
3070
 
  state->concatCTM(matrix[0], matrix[1], matrix[2],
3071
 
                   matrix[3], matrix[4], matrix[5]);
3072
 
  builder->setTransform(matrix[0], matrix[1], matrix[2],
3073
 
                        matrix[3], matrix[4], matrix[5]);
3074
 
 
3075
 
  // set form bounding box
3076
 
  state->moveTo(bbox[0], bbox[1]);
3077
 
  state->lineTo(bbox[2], bbox[1]);
3078
 
  state->lineTo(bbox[2], bbox[3]);
3079
 
  state->lineTo(bbox[0], bbox[3]);
3080
 
  state->closePath();
3081
 
  state->clip();
3082
 
  clipHistory->setClip(state->getPath());
3083
 
  builder->clip(state);
3084
 
  state->clearPath();
3085
 
 
3086
 
  if (softMask || transpGroup) {
3087
 
    if (state->getBlendMode() != gfxBlendNormal) {
3088
 
      state->setBlendMode(gfxBlendNormal);
3089
 
    }
3090
 
    if (state->getFillOpacity() != 1) {
3091
 
      builder->setGroupOpacity(state->getFillOpacity());
3092
 
      state->setFillOpacity(1);
3093
 
    }
3094
 
    if (state->getStrokeOpacity() != 1) {
3095
 
      state->setStrokeOpacity(1);
3096
 
    }
3097
 
  }
3098
 
 
3099
 
  // set new base matrix
3100
 
  for (i = 0; i < 6; ++i) {
3101
 
    oldBaseMatrix[i] = baseMatrix[i];
3102
 
    baseMatrix[i] = state->getCTM()[i];
3103
 
  }
3104
 
 
3105
 
  // draw the form
3106
 
  parse(str, gFalse);
3107
 
 
3108
 
  // restore base matrix
3109
 
  for (i = 0; i < 6; ++i) {
3110
 
    baseMatrix[i] = oldBaseMatrix[i];
3111
 
  }
3112
 
 
3113
 
  // restore parser
3114
 
  parser = oldParser;
3115
 
 
3116
 
  if (softMask || transpGroup) {
3117
 
      builder->popTransparencyGroup(state);
3118
 
  }
3119
 
 
3120
 
  // restore graphics state
3121
 
  restoreState();
3122
 
 
3123
 
  // pop resource stack
3124
 
  popResources();
3125
 
 
3126
 
  if (softMask) {
3127
 
    builder->setSoftMask(state, bbox, alpha, transferFunc, backdropColor);
3128
 
  } else if (transpGroup) {
3129
 
    builder->paintTransparencyGroup(state, bbox);
3130
 
  }
3131
 
 
3132
 
  return;
3133
 
}
3134
 
 
3135
 
//------------------------------------------------------------------------
3136
 
// in-line image operators
3137
 
//------------------------------------------------------------------------
3138
 
 
3139
 
void PdfParser::opBeginImage(Object args[], int numArgs) {
3140
 
  Stream *str;
3141
 
  int c1, c2;
3142
 
 
3143
 
  // build dict/stream
3144
 
  str = buildImageStream();
3145
 
 
3146
 
  // display the image
3147
 
  if (str) {
3148
 
    doImage(NULL, str, gTrue);
3149
 
  
3150
 
    // skip 'EI' tag
3151
 
    c1 = str->getUndecodedStream()->getChar();
3152
 
    c2 = str->getUndecodedStream()->getChar();
3153
 
    while (!(c1 == 'E' && c2 == 'I') && c2 != EOF) {
3154
 
      c1 = c2;
3155
 
      c2 = str->getUndecodedStream()->getChar();
3156
 
    }
3157
 
    delete str;
3158
 
  }
3159
 
}
3160
 
 
3161
 
Stream *PdfParser::buildImageStream() {
3162
 
  Object dict;
3163
 
  Object obj;
3164
 
  char *key;
3165
 
  Stream *str;
3166
 
 
3167
 
  // build dictionary
3168
 
  dict.initDict(xref);
3169
 
  parser->getObj(&obj);
3170
 
  while (!obj.isCmd(const_cast<char*>("ID")) && !obj.isEOF()) {
3171
 
    if (!obj.isName()) {
3172
 
#ifdef POPPLER_NEW_ERRORAPI
3173
 
      error(errSyntaxError, getPos(), "Inline image dictionary key must be a name object");
3174
 
#else
3175
 
      error(getPos(), const_cast<char*>("Inline image dictionary key must be a name object"));
3176
 
#endif
3177
 
      obj.free();
3178
 
    } else {
3179
 
      key = copyString(obj.getName());
3180
 
      obj.free();
3181
 
      parser->getObj(&obj);
3182
 
      if (obj.isEOF() || obj.isError()) {
3183
 
        gfree(key);
3184
 
        break;
3185
 
      }
3186
 
      dict.dictAdd(key, &obj);
3187
 
    }
3188
 
    parser->getObj(&obj);
3189
 
  }
3190
 
  if (obj.isEOF()) {
3191
 
#ifdef POPPLER_NEW_ERRORAPI
3192
 
    error(errSyntaxError, getPos(), "End of file in inline image");
3193
 
#else
3194
 
    error(getPos(), const_cast<char*>("End of file in inline image"));
3195
 
#endif
3196
 
    obj.free();
3197
 
    dict.free();
3198
 
    return NULL;
3199
 
  }
3200
 
  obj.free();
3201
 
 
3202
 
  // make stream
3203
 
  str = new EmbedStream(parser->getStream(), &dict, gFalse, 0);
3204
 
  str = str->addFilters(&dict);
3205
 
 
3206
 
  return str;
3207
 
}
3208
 
 
3209
 
void PdfParser::opImageData(Object args[], int numArgs) {
3210
 
#ifdef POPPLER_NEW_ERRORAPI
3211
 
  error(errInternal, getPos(), "Internal: got 'ID' operator");
3212
 
#else
3213
 
  error(getPos(), const_cast<char*>("Internal: got 'ID' operator"));
3214
 
#endif
3215
 
}
3216
 
 
3217
 
void PdfParser::opEndImage(Object args[], int numArgs) {
3218
 
#ifdef POPPLER_NEW_ERRORAPI
3219
 
  error(errInternal, getPos(), "Internal: got 'EI' operator");
3220
 
#else
3221
 
  error(getPos(), const_cast<char*>("Internal: got 'EI' operator"));
3222
 
#endif
3223
 
}
3224
 
 
3225
 
//------------------------------------------------------------------------
3226
 
// type 3 font operators
3227
 
//------------------------------------------------------------------------
3228
 
 
3229
 
void PdfParser::opSetCharWidth(Object args[], int numArgs) {
3230
 
}
3231
 
 
3232
 
void PdfParser::opSetCacheDevice(Object args[], int numArgs) {
3233
 
}
3234
 
 
3235
 
//------------------------------------------------------------------------
3236
 
// compatibility operators
3237
 
//------------------------------------------------------------------------
3238
 
 
3239
 
void PdfParser::opBeginIgnoreUndef(Object args[], int numArgs) {
3240
 
  ++ignoreUndef;
3241
 
}
3242
 
 
3243
 
void PdfParser::opEndIgnoreUndef(Object args[], int numArgs) {
3244
 
  if (ignoreUndef > 0)
3245
 
    --ignoreUndef;
3246
 
}
3247
 
 
3248
 
//------------------------------------------------------------------------
3249
 
// marked content operators
3250
 
//------------------------------------------------------------------------
3251
 
 
3252
 
void PdfParser::opBeginMarkedContent(Object args[], int numArgs) {
3253
 
  if (printCommands) {
3254
 
    printf("  marked content: %s ", args[0].getName());
3255
 
    if (numArgs == 2)
3256
 
      args[2].print(stdout);
3257
 
    printf("\n");
3258
 
    fflush(stdout);
3259
 
  }
3260
 
 
3261
 
  if(numArgs == 2) {
3262
 
    //out->beginMarkedContent(args[0].getName(),args[1].getDict());
3263
 
  } else {
3264
 
    //out->beginMarkedContent(args[0].getName());
3265
 
  }
3266
 
}
3267
 
 
3268
 
void PdfParser::opEndMarkedContent(Object args[], int numArgs) {
3269
 
  //out->endMarkedContent();
3270
 
}
3271
 
 
3272
 
void PdfParser::opMarkPoint(Object args[], int numArgs) {
3273
 
  if (printCommands) {
3274
 
    printf("  mark point: %s ", args[0].getName());
3275
 
    if (numArgs == 2)
3276
 
      args[2].print(stdout);
3277
 
    printf("\n");
3278
 
    fflush(stdout);
3279
 
  }
3280
 
 
3281
 
  if(numArgs == 2) {
3282
 
    //out->markPoint(args[0].getName(),args[1].getDict());
3283
 
  } else {
3284
 
    //out->markPoint(args[0].getName());
3285
 
  }
3286
 
 
3287
 
}
3288
 
 
3289
 
//------------------------------------------------------------------------
3290
 
// misc
3291
 
//------------------------------------------------------------------------
3292
 
 
3293
 
void PdfParser::saveState() {
3294
 
  builder->saveState();
3295
 
  state = state->save();
3296
 
  clipHistory = clipHistory->save();
3297
 
}
3298
 
 
3299
 
void PdfParser::restoreState() {
3300
 
  clipHistory = clipHistory->restore();
3301
 
  state = state->restore();
3302
 
  builder->restoreState();
3303
 
}
3304
 
 
3305
 
void PdfParser::pushResources(Dict *resDict) {
3306
 
  res = new GfxResources(xref, resDict, res);
3307
 
}
3308
 
 
3309
 
void PdfParser::popResources() {
3310
 
  GfxResources *resPtr;
3311
 
 
3312
 
  resPtr = res->getNext();
3313
 
  delete res;
3314
 
  res = resPtr;
3315
 
}
3316
 
 
3317
 
void PdfParser::setDefaultApproximationPrecision() {
3318
 
  int i;
3319
 
 
3320
 
  for (i = 1; i <= pdfNumShadingTypes; ++i) {
3321
 
    setApproximationPrecision(i, defaultShadingColorDelta, defaultShadingMaxDepth);
3322
 
  }
3323
 
}
3324
 
 
3325
 
void PdfParser::setApproximationPrecision(int shadingType, double colorDelta,
3326
 
                                          int maxDepth) {
3327
 
 
3328
 
  if (shadingType > pdfNumShadingTypes || shadingType < 1) {
3329
 
    return;
3330
 
  }
3331
 
  colorDeltas[shadingType-1] = dblToCol(colorDelta);
3332
 
  maxDepths[shadingType-1] = maxDepth;
3333
 
}
3334
 
 
3335
 
//------------------------------------------------------------------------
3336
 
// ClipHistoryEntry
3337
 
//------------------------------------------------------------------------
3338
 
 
3339
 
ClipHistoryEntry::ClipHistoryEntry(GfxPath *clipPathA, GfxClipType clipTypeA) {
3340
 
    if (clipPathA) {
3341
 
        clipPath = clipPathA->copy();
3342
 
    } else {
3343
 
        clipPath = NULL;
3344
 
    }
3345
 
    clipType = clipTypeA;
3346
 
    saved = NULL;
3347
 
}
3348
 
 
3349
 
ClipHistoryEntry::~ClipHistoryEntry() {
3350
 
    if (clipPath) {
3351
 
        delete clipPath;
3352
 
    }
3353
 
}
3354
 
 
3355
 
void ClipHistoryEntry::setClip(GfxPath *clipPathA, GfxClipType clipTypeA) {
3356
 
    // Free previous clip path
3357
 
    if (clipPath) {
3358
 
        delete clipPath;
3359
 
    }
3360
 
    if (clipPathA) {
3361
 
        clipPath = clipPathA->copy();
3362
 
        clipType = clipTypeA;
3363
 
    } else {
3364
 
        clipPath = NULL;
3365
 
    }
3366
 
}
3367
 
 
3368
 
ClipHistoryEntry *ClipHistoryEntry::save() {
3369
 
    ClipHistoryEntry *newEntry = new ClipHistoryEntry(this);
3370
 
    newEntry->saved = this;
3371
 
 
3372
 
    return newEntry;
3373
 
}
3374
 
 
3375
 
ClipHistoryEntry *ClipHistoryEntry::restore() {
3376
 
    ClipHistoryEntry *oldEntry;
3377
 
 
3378
 
    if (saved) {
3379
 
        oldEntry = saved;
3380
 
        saved = NULL;
3381
 
        delete this;
3382
 
    } else {
3383
 
        oldEntry = this;
3384
 
    }
3385
 
 
3386
 
    return oldEntry;
3387
 
}
3388
 
 
3389
 
ClipHistoryEntry::ClipHistoryEntry(ClipHistoryEntry *other) {
3390
 
    if (other->clipPath) {
3391
 
        this->clipPath = other->clipPath->copy();
3392
 
        this->clipType = other->clipType;
3393
 
    } else {
3394
 
        this->clipPath = NULL;
3395
 
    }
3396
 
    saved = NULL;
3397
 
}
3398
 
 
3399
 
#endif /* HAVE_POPPLER */