source: trunk/poppler/mypoppler/poppler/Function.cc @ 277

Last change on this file since 277 was 277, checked in by rbri, 11 years ago

PDF plugin: Poppler library updated to version 0.12.3

File size: 37.0 KB
Line 
1//========================================================================
2//
3// Function.cc
4//
5// Copyright 2001-2003 Glyph & Cog, LLC
6//
7//========================================================================
8
9//========================================================================
10//
11// Modified under the Poppler project - http://poppler.freedesktop.org
12//
13// All changes made under the Poppler project to this file are licensed
14// under GPL version 2 or later
15//
16// Copyright (C) 2006, 2008, 2009 Albert Astals Cid <aacid@kde.org>
17// Copyright (C) 2006 Jeff Muizelaar <jeff@infidigm.net>
18//
19// To see a description of the changes please see the Changelog file that
20// came with your tarball or type make ChangeLog if you are building from git
21//
22//========================================================================
23
24#include <config.h>
25
26#ifdef USE_GCC_PRAGMAS
27#pragma implementation
28#endif
29
30#include <stdlib.h>
31#include <string.h>
32#include <ctype.h>
33#include <math.h>
34#include "goo/gmem.h"
35#include "goo/gstrtod.h"
36#include "Object.h"
37#include "Dict.h"
38#include "Stream.h"
39#include "Error.h"
40#include "Function.h"
41#include "PopplerCache.h"
42
43#ifndef M_PI
44#define M_PI 3.14159265358979323846
45#endif
46
47//------------------------------------------------------------------------
48// Function
49//------------------------------------------------------------------------
50
51Function::Function() {
52}
53
54Function::~Function() {
55}
56
57Function *Function::parse(Object *funcObj) {
58  Function *func;
59  Dict *dict;
60  int funcType;
61  Object obj1;
62
63  if (funcObj->isStream()) {
64    dict = funcObj->streamGetDict();
65  } else if (funcObj->isDict()) {
66    dict = funcObj->getDict();
67  } else if (funcObj->isName("Identity")) {
68    return new IdentityFunction();
69  } else {
70    error(-1, "Expected function dictionary or stream");
71    return NULL;
72  }
73
74  if (!dict->lookup("FunctionType", &obj1)->isInt()) {
75    error(-1, "Function type is missing or wrong type");
76    obj1.free();
77    return NULL;
78  }
79  funcType = obj1.getInt();
80  obj1.free();
81
82  if (funcType == 0) {
83    func = new SampledFunction(funcObj, dict);
84  } else if (funcType == 2) {
85    func = new ExponentialFunction(funcObj, dict);
86  } else if (funcType == 3) {
87    func = new StitchingFunction(funcObj, dict);
88  } else if (funcType == 4) {
89    func = new PostScriptFunction(funcObj, dict);
90  } else {
91    error(-1, "Unimplemented function type (%d)", funcType);
92    return NULL;
93  }
94  if (!func->isOk()) {
95    delete func;
96    return NULL;
97  }
98
99  return func;
100}
101
102GBool Function::init(Dict *dict) {
103  Object obj1, obj2;
104  int i;
105
106  //----- Domain
107  if (!dict->lookup("Domain", &obj1)->isArray()) {
108    error(-1, "Function is missing domain");
109    goto err2;
110  }
111  m = obj1.arrayGetLength() / 2;
112  if (m > funcMaxInputs) {
113    error(-1, "Functions with more than %d inputs are unsupported",
114          funcMaxInputs);
115    goto err2;
116  }
117  for (i = 0; i < m; ++i) {
118    obj1.arrayGet(2*i, &obj2);
119    if (!obj2.isNum()) {
120      error(-1, "Illegal value in function domain array");
121      goto err1;
122    }
123    domain[i][0] = obj2.getNum();
124    obj2.free();
125    obj1.arrayGet(2*i+1, &obj2);
126    if (!obj2.isNum()) {
127      error(-1, "Illegal value in function domain array");
128      goto err1;
129    }
130    domain[i][1] = obj2.getNum();
131    obj2.free();
132  }
133  obj1.free();
134
135  //----- Range
136  hasRange = gFalse;
137  n = 0;
138  if (dict->lookup("Range", &obj1)->isArray()) {
139    hasRange = gTrue;
140    n = obj1.arrayGetLength() / 2;
141    if (n > funcMaxOutputs) {
142      error(-1, "Functions with more than %d outputs are unsupported",
143            funcMaxOutputs);
144      goto err2;
145    }
146    for (i = 0; i < n; ++i) {
147      obj1.arrayGet(2*i, &obj2);
148      if (!obj2.isNum()) {
149        error(-1, "Illegal value in function range array");
150        goto err1;
151      }
152      range[i][0] = obj2.getNum();
153      obj2.free();
154      obj1.arrayGet(2*i+1, &obj2);
155      if (!obj2.isNum()) {
156        error(-1, "Illegal value in function range array");
157        goto err1;
158      }
159      range[i][1] = obj2.getNum();
160      obj2.free();
161    }
162  }
163  obj1.free();
164
165  return gTrue;
166
167 err1:
168  obj2.free();
169 err2:
170  obj1.free();
171  return gFalse;
172}
173
174//------------------------------------------------------------------------
175// IdentityFunction
176//------------------------------------------------------------------------
177
178IdentityFunction::IdentityFunction() {
179  int i;
180
181  // fill these in with arbitrary values just in case they get used
182  // somewhere
183  m = funcMaxInputs;
184  n = funcMaxOutputs;
185  for (i = 0; i < funcMaxInputs; ++i) {
186    domain[i][0] = 0;
187    domain[i][1] = 1;
188  }
189  hasRange = gFalse;
190}
191
192IdentityFunction::~IdentityFunction() {
193}
194
195void IdentityFunction::transform(double *in, double *out) {
196  int i;
197
198  for (i = 0; i < funcMaxOutputs; ++i) {
199    out[i] = in[i];
200  }
201}
202
203//------------------------------------------------------------------------
204// SampledFunction
205//------------------------------------------------------------------------
206
207SampledFunction::SampledFunction(Object *funcObj, Dict *dict) {
208  Stream *str;
209  int sampleBits;
210  double sampleMul;
211  Object obj1, obj2;
212  Guint buf, bitMask;
213  int bits;
214  Guint s;
215  int i;
216
217  samples = NULL;
218  sBuf = NULL;
219  ok = gFalse;
220
221  //----- initialize the generic stuff
222  if (!init(dict)) {
223    goto err1;
224  }
225  if (!hasRange) {
226    error(-1, "Type 0 function is missing range");
227    goto err1;
228  }
229  if (m > sampledFuncMaxInputs) {
230    error(-1, "Sampled functions with more than %d inputs are unsupported",
231          sampledFuncMaxInputs);
232    goto err1;
233  }
234
235  //----- buffer
236  sBuf = (double *)gmallocn(1 << m, sizeof(double));
237
238  //----- get the stream
239  if (!funcObj->isStream()) {
240    error(-1, "Type 0 function isn't a stream");
241    goto err1;
242  }
243  str = funcObj->getStream();
244
245  //----- Size
246  if (!dict->lookup("Size", &obj1)->isArray() ||
247      obj1.arrayGetLength() != m) {
248    error(-1, "Function has missing or invalid size array");
249    goto err2;
250  }
251  for (i = 0; i < m; ++i) {
252    obj1.arrayGet(i, &obj2);
253    if (!obj2.isInt()) {
254      error(-1, "Illegal value in function size array");
255      goto err3;
256    }
257    sampleSize[i] = obj2.getInt();
258    obj2.free();
259  }
260  obj1.free();
261  idxMul[0] = n;
262  for (i = 1; i < m; ++i) {
263    idxMul[i] = idxMul[i-1] * sampleSize[i-1];
264  }
265
266  //----- BitsPerSample
267  if (!dict->lookup("BitsPerSample", &obj1)->isInt()) {
268    error(-1, "Function has missing or invalid BitsPerSample");
269    goto err2;
270  }
271  sampleBits = obj1.getInt();
272  sampleMul = 1.0 / (pow(2.0, (double)sampleBits) - 1);
273  obj1.free();
274
275  //----- Encode
276  if (dict->lookup("Encode", &obj1)->isArray() &&
277      obj1.arrayGetLength() == 2*m) {
278    for (i = 0; i < m; ++i) {
279      obj1.arrayGet(2*i, &obj2);
280      if (!obj2.isNum()) {
281        error(-1, "Illegal value in function encode array");
282        goto err3;
283      }
284      encode[i][0] = obj2.getNum();
285      obj2.free();
286      obj1.arrayGet(2*i+1, &obj2);
287      if (!obj2.isNum()) {
288        error(-1, "Illegal value in function encode array");
289        goto err3;
290      }
291      encode[i][1] = obj2.getNum();
292      obj2.free();
293    }
294  } else {
295    for (i = 0; i < m; ++i) {
296      encode[i][0] = 0;
297      encode[i][1] = sampleSize[i] - 1;
298    }
299  }
300  obj1.free();
301  for (i = 0; i < m; ++i) {
302    inputMul[i] = (encode[i][1] - encode[i][0]) /
303                  (domain[i][1] - domain[i][0]);
304  }
305
306  //----- Decode
307  if (dict->lookup("Decode", &obj1)->isArray() &&
308      obj1.arrayGetLength() == 2*n) {
309    for (i = 0; i < n; ++i) {
310      obj1.arrayGet(2*i, &obj2);
311      if (!obj2.isNum()) {
312        error(-1, "Illegal value in function decode array");
313        goto err3;
314      }
315      decode[i][0] = obj2.getNum();
316      obj2.free();
317      obj1.arrayGet(2*i+1, &obj2);
318      if (!obj2.isNum()) {
319        error(-1, "Illegal value in function decode array");
320        goto err3;
321      }
322      decode[i][1] = obj2.getNum();
323      obj2.free();
324    }
325  } else {
326    for (i = 0; i < n; ++i) {
327      decode[i][0] = range[i][0];
328      decode[i][1] = range[i][1];
329    }
330  }
331  obj1.free();
332
333  //----- samples
334  nSamples = n;
335  for (i = 0; i < m; ++i)
336    nSamples *= sampleSize[i];
337  samples = (double *)gmallocn(nSamples, sizeof(double));
338  buf = 0;
339  bits = 0;
340  bitMask = (1 << sampleBits) - 1;
341  str->reset();
342  for (i = 0; i < nSamples; ++i) {
343    if (sampleBits == 8) {
344      s = str->getChar();
345    } else if (sampleBits == 16) {
346      s = str->getChar();
347      s = (s << 8) + str->getChar();
348    } else if (sampleBits == 32) {
349      s = str->getChar();
350      s = (s << 8) + str->getChar();
351      s = (s << 8) + str->getChar();
352      s = (s << 8) + str->getChar();
353    } else {
354      while (bits < sampleBits) {
355        buf = (buf << 8) | (str->getChar() & 0xff);
356        bits += 8;
357      }
358      s = (buf >> (bits - sampleBits)) & bitMask;
359      bits -= sampleBits;
360    }
361    samples[i] = (double)s * sampleMul;
362  }
363  str->close();
364
365  ok = gTrue;
366  return;
367
368 err3:
369  obj2.free();
370 err2:
371  obj1.free();
372 err1:
373  return;
374}
375
376SampledFunction::~SampledFunction() {
377  if (samples) {
378    gfree(samples);
379  }
380  if (sBuf) {
381    gfree(sBuf);
382  }
383}
384
385SampledFunction::SampledFunction(SampledFunction *func) {
386  memcpy(this, func, sizeof(SampledFunction));
387  samples = (double *)gmallocn(nSamples, sizeof(double));
388  memcpy(samples, func->samples, nSamples * sizeof(double));
389  sBuf = (double *)gmallocn(1 << m, sizeof(double));
390}
391
392void SampledFunction::transform(double *in, double *out) {
393  double x;
394  int e[funcMaxInputs][2];
395  double efrac0[funcMaxInputs];
396  double efrac1[funcMaxInputs];
397  int i, j, k, idx, t;
398
399  // map input values into sample array
400  for (i = 0; i < m; ++i) {
401    x = (in[i] - domain[i][0]) * inputMul[i] + encode[i][0];
402    if (x < 0) {
403      x = 0;
404    } else if (x > sampleSize[i] - 1) {
405      x = sampleSize[i] - 1;
406    }
407    e[i][0] = (int)x;
408    if ((e[i][1] = e[i][0] + 1) >= sampleSize[i]) {
409      // this happens if in[i] = domain[i][1]
410      e[i][1] = e[i][0];
411    }
412    efrac1[i] = x - e[i][0];
413    efrac0[i] = 1 - efrac1[i];
414  }
415
416  // for each output, do m-linear interpolation
417  for (i = 0; i < n; ++i) {
418
419    // pull 2^m values out of the sample array
420    for (j = 0; j < (1<<m); ++j) {
421      idx = i;
422      for (k = 0, t = j; k < m; ++k, t >>= 1) {
423        idx += idxMul[k] * (e[k][t & 1]);
424      }
425      sBuf[j] = samples[idx];
426    }
427
428    // do m sets of interpolations
429    for (j = 0, t = (1<<m); j < m; ++j, t >>= 1) {
430      for (k = 0; k < t; k += 2) {
431        sBuf[k >> 1] = efrac0[j] * sBuf[k] + efrac1[j] * sBuf[k+1];
432      }
433    }
434
435    // map output value to range
436    out[i] = sBuf[0] * (decode[i][1] - decode[i][0]) + decode[i][0];
437    if (out[i] < range[i][0]) {
438      out[i] = range[i][0];
439    } else if (out[i] > range[i][1]) {
440      out[i] = range[i][1];
441    }
442  }
443}
444
445//------------------------------------------------------------------------
446// ExponentialFunction
447//------------------------------------------------------------------------
448
449ExponentialFunction::ExponentialFunction(Object *funcObj, Dict *dict) {
450  Object obj1, obj2;
451  int i;
452
453  ok = gFalse;
454
455  //----- initialize the generic stuff
456  if (!init(dict)) {
457    goto err1;
458  }
459  if (m != 1) {
460    error(-1, "Exponential function with more than one input");
461    goto err1;
462  }
463
464  //----- C0
465  if (dict->lookup("C0", &obj1)->isArray()) {
466    if (hasRange && obj1.arrayGetLength() != n) {
467      error(-1, "Function's C0 array is wrong length");
468      goto err2;
469    }
470    n = obj1.arrayGetLength();
471    for (i = 0; i < n; ++i) {
472      obj1.arrayGet(i, &obj2);
473      if (!obj2.isNum()) {
474        error(-1, "Illegal value in function C0 array");
475        goto err3;
476      }
477      c0[i] = obj2.getNum();
478      obj2.free();
479    }
480  } else {
481    if (hasRange && n != 1) {
482      error(-1, "Function's C0 array is wrong length");
483      goto err2;
484    }
485    n = 1;
486    c0[0] = 0;
487  }
488  obj1.free();
489
490  //----- C1
491  if (dict->lookup("C1", &obj1)->isArray()) {
492    if (obj1.arrayGetLength() != n) {
493      error(-1, "Function's C1 array is wrong length");
494      goto err2;
495    }
496    for (i = 0; i < n; ++i) {
497      obj1.arrayGet(i, &obj2);
498      if (!obj2.isNum()) {
499        error(-1, "Illegal value in function C1 array");
500        goto err3;
501      }
502      c1[i] = obj2.getNum();
503      obj2.free();
504    }
505  } else {
506    if (n != 1) {
507      error(-1, "Function's C1 array is wrong length");
508      goto err2;
509    }
510    c1[0] = 1;
511  }
512  obj1.free();
513
514  //----- N (exponent)
515  if (!dict->lookup("N", &obj1)->isNum()) {
516    error(-1, "Function has missing or invalid N");
517    goto err2;
518  }
519  e = obj1.getNum();
520  obj1.free();
521
522  ok = gTrue;
523  return;
524
525 err3:
526  obj2.free();
527 err2:
528  obj1.free();
529 err1:
530  return;
531}
532
533ExponentialFunction::~ExponentialFunction() {
534}
535
536ExponentialFunction::ExponentialFunction(ExponentialFunction *func) {
537  memcpy(this, func, sizeof(ExponentialFunction));
538}
539
540void ExponentialFunction::transform(double *in, double *out) {
541  double x;
542  int i;
543
544  if (in[0] < domain[0][0]) {
545    x = domain[0][0];
546  } else if (in[0] > domain[0][1]) {
547    x = domain[0][1];
548  } else {
549    x = in[0];
550  }
551  for (i = 0; i < n; ++i) {
552    out[i] = c0[i] + pow(x, e) * (c1[i] - c0[i]);
553    if (hasRange) {
554      if (out[i] < range[i][0]) {
555        out[i] = range[i][0];
556      } else if (out[i] > range[i][1]) {
557        out[i] = range[i][1];
558      }
559    }
560  }
561  return;
562}
563
564//------------------------------------------------------------------------
565// StitchingFunction
566//------------------------------------------------------------------------
567
568StitchingFunction::StitchingFunction(Object *funcObj, Dict *dict) {
569  Object obj1, obj2;
570  int i;
571
572  ok = gFalse;
573  funcs = NULL;
574  bounds = NULL;
575  encode = NULL;
576  scale = NULL;
577
578  //----- initialize the generic stuff
579  if (!init(dict)) {
580    goto err1;
581  }
582  if (m != 1) {
583    error(-1, "Stitching function with more than one input");
584    goto err1;
585  }
586
587  //----- Functions
588  if (!dict->lookup("Functions", &obj1)->isArray()) {
589    error(-1, "Missing 'Functions' entry in stitching function");
590    goto err1;
591  }
592  k = obj1.arrayGetLength();
593  funcs = (Function **)gmallocn(k, sizeof(Function *));
594  bounds = (double *)gmallocn(k + 1, sizeof(double));
595  encode = (double *)gmallocn(2 * k, sizeof(double));
596  scale = (double *)gmallocn(k, sizeof(double));
597  for (i = 0; i < k; ++i) {
598    funcs[i] = NULL;
599  }
600  for (i = 0; i < k; ++i) {
601    if (!(funcs[i] = Function::parse(obj1.arrayGet(i, &obj2)))) {
602      goto err2;
603    }
604    if (i > 0 && (funcs[i]->getInputSize() != 1 ||
605                  funcs[i]->getOutputSize() != funcs[0]->getOutputSize())) {
606      error(-1, "Incompatible subfunctions in stitching function");
607      goto err2;
608    }
609    obj2.free();
610  }
611  obj1.free();
612
613  //----- Bounds
614  if (!dict->lookup("Bounds", &obj1)->isArray() ||
615      obj1.arrayGetLength() != k - 1) {
616    error(-1, "Missing or invalid 'Bounds' entry in stitching function");
617    goto err1;
618  }
619  bounds[0] = domain[0][0];
620  for (i = 1; i < k; ++i) {
621    if (!obj1.arrayGet(i - 1, &obj2)->isNum()) {
622      error(-1, "Invalid type in 'Bounds' array in stitching function");
623      goto err2;
624    }
625    bounds[i] = obj2.getNum();
626    obj2.free();
627  }
628  bounds[k] = domain[0][1];
629  obj1.free();
630
631  //----- Encode
632  if (!dict->lookup("Encode", &obj1)->isArray() ||
633      obj1.arrayGetLength() != 2 * k) {
634    error(-1, "Missing or invalid 'Encode' entry in stitching function");
635    goto err1;
636  }
637  for (i = 0; i < 2 * k; ++i) {
638    if (!obj1.arrayGet(i, &obj2)->isNum()) {
639      error(-1, "Invalid type in 'Encode' array in stitching function");
640      goto err2;
641    }
642    encode[i] = obj2.getNum();
643    obj2.free();
644  }
645  obj1.free();
646
647  //----- pre-compute the scale factors
648  for (i = 0; i < k; ++i) {
649    if (bounds[i] == bounds[i+1]) {
650      // avoid a divide-by-zero -- in this situation, function i will
651      // never be used anyway
652      scale[i] = 0;
653    } else {
654      scale[i] = (encode[2*i+1] - encode[2*i]) / (bounds[i+1] - bounds[i]);
655    }
656  }
657
658  ok = gTrue;
659  return;
660
661 err2:
662  obj2.free();
663 err1:
664  obj1.free();
665}
666
667StitchingFunction::StitchingFunction(StitchingFunction *func) {
668  int i;
669
670  memcpy(this, func, sizeof(StitchingFunction));
671
672  k = func->k;
673  funcs = (Function **)gmallocn(k, sizeof(Function *));
674  for (i = 0; i < k; ++i) {
675    funcs[i] = func->funcs[i]->copy();
676  }
677  bounds = (double *)gmallocn(k + 1, sizeof(double));
678  memcpy(bounds, func->bounds, (k + 1) * sizeof(double));
679  encode = (double *)gmallocn(2 * k, sizeof(double));
680  memcpy(encode, func->encode, 2 * k * sizeof(double));
681  scale = (double *)gmallocn(k, sizeof(double));
682  memcpy(scale, func->scale, k * sizeof(double));
683  ok = gTrue;
684}
685
686StitchingFunction::~StitchingFunction() {
687  int i;
688
689  if (funcs) {
690    for (i = 0; i < k; ++i) {
691      if (funcs[i]) {
692        delete funcs[i];
693      }
694    }
695  }
696  gfree(funcs);
697  gfree(bounds);
698  gfree(encode);
699  gfree(scale);
700}
701
702void StitchingFunction::transform(double *in, double *out) {
703  double x;
704  int i;
705
706  if (in[0] < domain[0][0]) {
707    x = domain[0][0];
708  } else if (in[0] > domain[0][1]) {
709    x = domain[0][1];
710  } else {
711    x = in[0];
712  }
713  for (i = 0; i < k - 1; ++i) {
714    if (x < bounds[i+1]) {
715      break;
716    }
717  }
718  x = encode[2*i] + (x - bounds[i]) * scale[i];
719  funcs[i]->transform(&x, out);
720}
721
722//------------------------------------------------------------------------
723// PostScriptFunction
724//------------------------------------------------------------------------
725
726enum PSOp {
727  psOpAbs,
728  psOpAdd,
729  psOpAnd,
730  psOpAtan,
731  psOpBitshift,
732  psOpCeiling,
733  psOpCopy,
734  psOpCos,
735  psOpCvi,
736  psOpCvr,
737  psOpDiv,
738  psOpDup,
739  psOpEq,
740  psOpExch,
741  psOpExp,
742  psOpFalse,
743  psOpFloor,
744  psOpGe,
745  psOpGt,
746  psOpIdiv,
747  psOpIndex,
748  psOpLe,
749  psOpLn,
750  psOpLog,
751  psOpLt,
752  psOpMod,
753  psOpMul,
754  psOpNe,
755  psOpNeg,
756  psOpNot,
757  psOpOr,
758  psOpPop,
759  psOpRoll,
760  psOpRound,
761  psOpSin,
762  psOpSqrt,
763  psOpSub,
764  psOpTrue,
765  psOpTruncate,
766  psOpXor,
767  psOpIf,
768  psOpIfelse,
769  psOpReturn
770};
771
772// Note: 'if' and 'ifelse' are parsed separately.
773// The rest are listed here in alphabetical order.
774// The index in this table is equivalent to the entry in PSOp.
775static const char *psOpNames[] = {
776  "abs",
777  "add",
778  "and",
779  "atan",
780  "bitshift",
781  "ceiling",
782  "copy",
783  "cos",
784  "cvi",
785  "cvr",
786  "div",
787  "dup",
788  "eq",
789  "exch",
790  "exp",
791  "false",
792  "floor",
793  "ge",
794  "gt",
795  "idiv",
796  "index",
797  "le",
798  "ln",
799  "log",
800  "lt",
801  "mod",
802  "mul",
803  "ne",
804  "neg",
805  "not",
806  "or",
807  "pop",
808  "roll",
809  "round",
810  "sin",
811  "sqrt",
812  "sub",
813  "true",
814  "truncate",
815  "xor"
816};
817
818#define nPSOps (sizeof(psOpNames) / sizeof(char *))
819
820enum PSObjectType {
821  psBool,
822  psInt,
823  psReal,
824  psOperator,
825  psBlock
826};
827
828// In the code array, 'if'/'ifelse' operators take up three slots
829// plus space for the code in the subclause(s).
830//
831//         +---------------------------------+
832//         | psOperator: psOpIf / psOpIfelse |
833//         +---------------------------------+
834//         | psBlock: ptr=<A>                |
835//         +---------------------------------+
836//         | psBlock: ptr=<B>                |
837//         +---------------------------------+
838//         | if clause                       |
839//         | ...                             |
840//         | psOperator: psOpReturn          |
841//         +---------------------------------+
842//     <A> | else clause                     |
843//         | ...                             |
844//         | psOperator: psOpReturn          |
845//         +---------------------------------+
846//     <B> | ...                             |
847//
848// For 'if', pointer <A> is present in the code stream but unused.
849
850struct PSObject {
851  PSObjectType type;
852  union {
853    GBool booln;                // boolean (stack only)
854    int intg;                   // integer (stack and code)
855    double real;                // real (stack and code)
856    PSOp op;                    // operator (code only)
857    int blk;                    // if/ifelse block pointer (code only)
858  };
859};
860
861#define psStackSize 100
862
863class PSStack {
864public:
865
866  PSStack() {sp = psStackSize; }
867  void clear() { sp = psStackSize; }
868  void pushBool(GBool booln)
869  {
870    if (checkOverflow()) {
871      stack[--sp].type = psBool;
872      stack[sp].booln = booln;
873    }
874  }
875  void pushInt(int intg)
876  {
877    if (checkOverflow()) {
878      stack[--sp].type = psInt;
879      stack[sp].intg = intg;
880    }
881  }
882  void pushReal(double real)
883  {
884    if (checkOverflow()) {
885      stack[--sp].type = psReal;
886      stack[sp].real = real;
887    }
888  }
889  GBool popBool()
890  {
891    if (checkUnderflow() && checkType(psBool, psBool)) {
892      return stack[sp++].booln;
893    }
894    return gFalse;
895  }
896  int popInt()
897  {
898    if (checkUnderflow() && checkType(psInt, psInt)) {
899      return stack[sp++].intg;
900    }
901    return 0;
902  }
903  double popNum()
904  {
905    double ret;
906
907    if (checkUnderflow() && checkType(psInt, psReal)) {
908      ret = (stack[sp].type == psInt) ? (double)stack[sp].intg : stack[sp].real;
909      ++sp;
910      return ret;
911    }
912    return 0;
913  }
914  GBool empty() { return sp == psStackSize; }
915  GBool topIsInt() { return sp < psStackSize && stack[sp].type == psInt; }
916  GBool topTwoAreInts()
917    { return sp < psStackSize - 1 &&
918             stack[sp].type == psInt &&
919             stack[sp+1].type == psInt; }
920  GBool topIsReal() { return sp < psStackSize && stack[sp].type == psReal; }
921  GBool topTwoAreNums()
922    { return sp < psStackSize - 1 &&
923             (stack[sp].type == psInt || stack[sp].type == psReal) &&
924             (stack[sp+1].type == psInt || stack[sp+1].type == psReal); }
925  void copy(int n);
926  void roll(int n, int j);
927  void index(int i)
928  {
929    if (!checkOverflow()) {
930      return;
931    }
932    --sp;
933    stack[sp] = stack[sp + 1 + i];
934  }
935  void pop()
936  {
937    if (!checkUnderflow()) {
938      return;
939    }
940    ++sp;
941  }
942
943private:
944
945  GBool checkOverflow(int n = 1)
946  {
947    if (sp - n < 0) {
948      error(-1, "Stack overflow in PostScript function");
949      return gFalse;
950    }
951    return gTrue;
952  }
953  GBool checkUnderflow()
954  {
955    if (sp == psStackSize) {
956      error(-1, "Stack underflow in PostScript function");
957      return gFalse;
958    }
959    return gTrue;
960  }
961  GBool checkType(PSObjectType t1, PSObjectType t2)
962  {
963    if (stack[sp].type != t1 && stack[sp].type != t2) {
964      error(-1, "Type mismatch in PostScript function");
965      return gFalse;
966    }
967    return gTrue;
968  }
969  PSObject stack[psStackSize];
970  int sp;
971};
972
973
974void PSStack::copy(int n) {
975  int i;
976
977  if (sp + n > psStackSize) {
978    error(-1, "Stack underflow in PostScript function");
979    return;
980  }
981  if (!checkOverflow(n)) {
982    return;
983  }
984  for (i = sp + n - 1; i >= sp; --i) {
985    stack[i - n] = stack[i];
986  }
987  sp -= n;
988}
989
990void PSStack::roll(int n, int j) {
991  PSObject obj;
992  int i, k;
993
994  if (j >= 0) {
995    j %= n;
996  } else {
997    j = -j % n;
998    if (j != 0) {
999      j = n - j;
1000    }
1001  }
1002  if (n <= 0 || j == 0) {
1003    return;
1004  }
1005  if (j <= n / 2) {
1006    for (i = 0; i < j; ++i) {
1007      obj = stack[sp];
1008      for (k = sp; k < sp + n - 1; ++k) {
1009        stack[k] = stack[k+1];
1010      }
1011      stack[sp + n - 1] = obj;
1012    }
1013  } else {
1014    j = n - j;
1015    obj = stack[sp + n - 1];
1016    for (k = sp + n - 1; k > sp; --k) {
1017      stack[k] = stack[k-1];
1018    }
1019    stack[sp] = obj;
1020  }
1021}
1022
1023class PostScriptFunctionKey : public PopplerCacheKey
1024{
1025  public:
1026    PostScriptFunctionKey(int sizeA, double *inA, bool copyA)
1027    {
1028      init(sizeA, inA, copyA);
1029    }
1030   
1031    PostScriptFunctionKey(const PostScriptFunctionKey &key)
1032    {
1033      init(key.size, key.in, key.copied);
1034    }
1035   
1036    void init(int sizeA, double *inA, bool copyA)
1037    {
1038      copied = copyA;
1039      size = sizeA;
1040      if (copied) {
1041        in = new double[size];
1042        for (int i = 0; i < size; ++i) in[i] = inA[i];
1043      } else {
1044        in = inA;
1045      }
1046    }
1047   
1048    ~PostScriptFunctionKey()
1049    {
1050      if (copied) delete[] in;
1051    }
1052       
1053    bool operator==(const PopplerCacheKey &key) const
1054    {
1055      const PostScriptFunctionKey *k = static_cast<const PostScriptFunctionKey*>(&key);
1056      if (size == k->size) {
1057        bool equal = true;
1058        for (int i = 0; equal && i < size; ++i) {
1059          equal = in[i] == k->in[i];
1060        }
1061        return equal;
1062      } else {
1063        return false;
1064      }
1065    }
1066 
1067    bool copied;
1068    int size;
1069    double *in;
1070};
1071
1072class PostScriptFunctionItem : public PopplerCacheItem
1073{
1074  public:
1075    PostScriptFunctionItem(int sizeA, double *outA)
1076    {
1077      init(sizeA, outA);
1078    }
1079   
1080    PostScriptFunctionItem(const PostScriptFunctionItem &item)
1081    {
1082      init(item.size, item.out);
1083    }
1084   
1085    void init(int sizeA, double *outA)
1086    {
1087      size = sizeA;
1088      out = new double[size];
1089      for (int i = 0; i < size; ++i) out[i] = outA[i];
1090    }
1091   
1092    ~PostScriptFunctionItem()
1093    {
1094      delete[] out;
1095    }
1096   
1097    int size;
1098    double *out;
1099};
1100
1101PostScriptFunction::PostScriptFunction(Object *funcObj, Dict *dict) {
1102  Stream *str;
1103  int codePtr;
1104  GooString *tok;
1105
1106  code = NULL;
1107  codeString = NULL;
1108  codeSize = 0;
1109  ok = gFalse;
1110  cache = new PopplerCache(5);
1111
1112  //----- initialize the generic stuff
1113  if (!init(dict)) {
1114    goto err1;
1115  }
1116  if (!hasRange) {
1117    error(-1, "Type 4 function is missing range");
1118    goto err1;
1119  }
1120
1121  //----- get the stream
1122  if (!funcObj->isStream()) {
1123    error(-1, "Type 4 function isn't a stream");
1124    goto err1;
1125  }
1126  str = funcObj->getStream();
1127
1128  //----- parse the function
1129  codeString = new GooString();
1130  str->reset();
1131  if (!(tok = getToken(str)) || tok->cmp("{")) {
1132    error(-1, "Expected '{' at start of PostScript function");
1133    if (tok) {
1134      delete tok;
1135    }
1136    goto err1;
1137  }
1138  delete tok;
1139  codePtr = 0;
1140  if (!parseCode(str, &codePtr)) {
1141    goto err2;
1142  }
1143  str->close();
1144
1145  ok = gTrue;
1146 
1147  stack = new PSStack();
1148
1149 err2:
1150  str->close();
1151 err1:
1152  return;
1153}
1154
1155PostScriptFunction::PostScriptFunction(PostScriptFunction *func) {
1156  memcpy(this, func, sizeof(PostScriptFunction));
1157  code = (PSObject *)gmallocn(codeSize, sizeof(PSObject));
1158  memcpy(code, func->code, codeSize * sizeof(PSObject));
1159  codeString = func->codeString->copy();
1160  stack = new PSStack();
1161  memcpy(stack, func->stack, sizeof(PSStack));
1162 
1163  cache = new PopplerCache(func->cache->size());
1164  for (int i = 0; i < func->cache->numberOfItems(); ++i)
1165  {
1166    PostScriptFunctionKey *key = new PostScriptFunctionKey(*(PostScriptFunctionKey*)func->cache->key(i));
1167    PostScriptFunctionItem *item = new PostScriptFunctionItem(*(PostScriptFunctionItem*)func->cache->item(i));
1168    cache->put(key, item);
1169  }
1170}
1171
1172PostScriptFunction::~PostScriptFunction() {
1173  gfree(code);
1174  delete codeString;
1175  delete stack;
1176  delete cache;
1177}
1178
1179void PostScriptFunction::transform(double *in, double *out) {
1180  int i;
1181 
1182  PostScriptFunctionKey key(m, in, false);
1183  PopplerCacheItem *item = cache->lookup(key);
1184  if (item) {
1185    PostScriptFunctionItem *it = static_cast<PostScriptFunctionItem *>(item);
1186    for (int i = 0; i < n; ++i) {
1187      out[i] = it->out[i];
1188    }
1189    return;
1190  }
1191
1192  stack->clear();
1193  for (i = 0; i < m; ++i) {
1194    //~ may need to check for integers here
1195    stack->pushReal(in[i]);
1196  }
1197  exec(stack, 0);
1198  for (i = n - 1; i >= 0; --i) {
1199    out[i] = stack->popNum();
1200    if (out[i] < range[i][0]) {
1201      out[i] = range[i][0];
1202    } else if (out[i] > range[i][1]) {
1203      out[i] = range[i][1];
1204    }
1205  }
1206
1207  PostScriptFunctionKey *newKey = new PostScriptFunctionKey(m, in, true);
1208  PostScriptFunctionItem *newItem = new PostScriptFunctionItem(n, out);
1209  cache->put(newKey, newItem);
1210 
1211  // if (!stack->empty()) {
1212  //   error(-1, "Extra values on stack at end of PostScript function");
1213  // }
1214}
1215
1216GBool PostScriptFunction::parseCode(Stream *str, int *codePtr) {
1217  GooString *tok;
1218  char *p;
1219  GBool isReal;
1220  int opPtr, elsePtr;
1221  int a, b, mid, cmp;
1222
1223  while (1) {
1224    if (!(tok = getToken(str))) {
1225      error(-1, "Unexpected end of PostScript function stream");
1226      return gFalse;
1227    }
1228    p = tok->getCString();
1229    if (isdigit(*p) || *p == '.' || *p == '-') {
1230      isReal = gFalse;
1231      for (++p; *p; ++p) {
1232        if (*p == '.') {
1233          isReal = gTrue;
1234          break;
1235        }
1236      }
1237      resizeCode(*codePtr);
1238      if (isReal) {
1239        code[*codePtr].type = psReal;
1240          code[*codePtr].real = gatof(tok->getCString());
1241      } else {
1242        code[*codePtr].type = psInt;
1243        code[*codePtr].intg = atoi(tok->getCString());
1244      }
1245      ++*codePtr;
1246      delete tok;
1247    } else if (!tok->cmp("{")) {
1248      delete tok;
1249      opPtr = *codePtr;
1250      *codePtr += 3;
1251      resizeCode(opPtr + 2);
1252      if (!parseCode(str, codePtr)) {
1253        return gFalse;
1254      }
1255      if (!(tok = getToken(str))) {
1256        error(-1, "Unexpected end of PostScript function stream");
1257        return gFalse;
1258      }
1259      if (!tok->cmp("{")) {
1260        elsePtr = *codePtr;
1261        if (!parseCode(str, codePtr)) {
1262          return gFalse;
1263        }
1264        delete tok;
1265        if (!(tok = getToken(str))) {
1266          error(-1, "Unexpected end of PostScript function stream");
1267          return gFalse;
1268        }
1269      } else {
1270        elsePtr = -1;
1271      }
1272      if (!tok->cmp("if")) {
1273        if (elsePtr >= 0) {
1274          error(-1, "Got 'if' operator with two blocks in PostScript function");
1275          return gFalse;
1276        }
1277        code[opPtr].type = psOperator;
1278        code[opPtr].op = psOpIf;
1279        code[opPtr+2].type = psBlock;
1280        code[opPtr+2].blk = *codePtr;
1281      } else if (!tok->cmp("ifelse")) {
1282        if (elsePtr < 0) {
1283          error(-1, "Got 'ifelse' operator with one blocks in PostScript function");
1284          return gFalse;
1285        }
1286        code[opPtr].type = psOperator;
1287        code[opPtr].op = psOpIfelse;
1288        code[opPtr+1].type = psBlock;
1289        code[opPtr+1].blk = elsePtr;
1290        code[opPtr+2].type = psBlock;
1291        code[opPtr+2].blk = *codePtr;
1292      } else {
1293        error(-1, "Expected if/ifelse operator in PostScript function");
1294        delete tok;
1295        return gFalse;
1296      }
1297      delete tok;
1298    } else if (!tok->cmp("}")) {
1299      delete tok;
1300      resizeCode(*codePtr);
1301      code[*codePtr].type = psOperator;
1302      code[*codePtr].op = psOpReturn;
1303      ++*codePtr;
1304      break;
1305    } else {
1306      a = -1;
1307      b = nPSOps;
1308      // invariant: psOpNames[a] < tok < psOpNames[b]
1309      while (b - a > 1) {
1310        mid = (a + b) / 2;
1311        cmp = tok->cmp(psOpNames[mid]);
1312        if (cmp > 0) {
1313          a = mid;
1314        } else if (cmp < 0) {
1315          b = mid;
1316        } else {
1317          a = b = mid;
1318        }
1319      }
1320      if (cmp != 0) {
1321        error(-1, "Unknown operator '%s' in PostScript function",
1322              tok->getCString());
1323        delete tok;
1324        return gFalse;
1325      }
1326      delete tok;
1327      resizeCode(*codePtr);
1328      code[*codePtr].type = psOperator;
1329      code[*codePtr].op = (PSOp)a;
1330      ++*codePtr;
1331    }
1332  }
1333  return gTrue;
1334}
1335
1336GooString *PostScriptFunction::getToken(Stream *str) {
1337  GooString *s;
1338  int c;
1339  GBool comment;
1340
1341  s = new GooString();
1342  comment = gFalse;
1343  while (1) {
1344    if ((c = str->getChar()) == EOF) {
1345      break;
1346    }
1347    codeString->append(c);
1348    if (comment) {
1349      if (c == '\x0a' || c == '\x0d') {
1350        comment = gFalse;
1351      }
1352    } else if (c == '%') {
1353      comment = gTrue;
1354    } else if (!isspace(c)) {
1355      break;
1356    }
1357  }
1358  if (c == '{' || c == '}') {
1359    s->append((char)c);
1360  } else if (isdigit(c) || c == '.' || c == '-') {
1361    while (1) {
1362      s->append((char)c);
1363      c = str->lookChar();
1364      if (c == EOF || !(isdigit(c) || c == '.' || c == '-')) {
1365        break;
1366      }
1367      str->getChar();
1368      codeString->append(c);
1369    }
1370  } else {
1371    while (1) {
1372      s->append((char)c);
1373      c = str->lookChar();
1374      if (c == EOF || !isalnum(c)) {
1375        break;
1376      }
1377      str->getChar();
1378      codeString->append(c);
1379    }
1380  }
1381  return s;
1382}
1383
1384void PostScriptFunction::resizeCode(int newSize) {
1385  if (newSize >= codeSize) {
1386    codeSize += 64;
1387    code = (PSObject *)greallocn(code, codeSize, sizeof(PSObject));
1388  }
1389}
1390
1391void PostScriptFunction::exec(PSStack *stack, int codePtr) {
1392  int i1, i2;
1393  double r1, r2, result;
1394  GBool b1, b2;
1395
1396  while (1) {
1397    switch (code[codePtr].type) {
1398    case psInt:
1399      stack->pushInt(code[codePtr++].intg);
1400      break;
1401    case psReal:
1402      stack->pushReal(code[codePtr++].real);
1403      break;
1404    case psOperator:
1405      switch (code[codePtr++].op) {
1406      case psOpAbs:
1407        if (stack->topIsInt()) {
1408          stack->pushInt(abs(stack->popInt()));
1409        } else {
1410          stack->pushReal(fabs(stack->popNum()));
1411        }
1412        break;
1413      case psOpAdd:
1414        if (stack->topTwoAreInts()) {
1415          i2 = stack->popInt();
1416          i1 = stack->popInt();
1417          stack->pushInt(i1 + i2);
1418        } else {
1419          r2 = stack->popNum();
1420          r1 = stack->popNum();
1421          stack->pushReal(r1 + r2);
1422        }
1423        break;
1424      case psOpAnd:
1425        if (stack->topTwoAreInts()) {
1426          i2 = stack->popInt();
1427          i1 = stack->popInt();
1428          stack->pushInt(i1 & i2);
1429        } else {
1430          b2 = stack->popBool();
1431          b1 = stack->popBool();
1432          stack->pushBool(b1 && b2);
1433        }
1434        break;
1435      case psOpAtan:
1436        r2 = stack->popNum();
1437        r1 = stack->popNum();
1438        result = atan2(r1, r2) * 180.0 / M_PI;
1439        if (result < 0) result += 360.0;
1440        stack->pushReal(result);
1441        break;
1442      case psOpBitshift:
1443        i2 = stack->popInt();
1444        i1 = stack->popInt();
1445        if (i2 > 0) {
1446          stack->pushInt(i1 << i2);
1447        } else if (i2 < 0) {
1448          stack->pushInt((int)((Guint)i1 >> i2));
1449        } else {
1450          stack->pushInt(i1);
1451        }
1452        break;
1453      case psOpCeiling:
1454        if (!stack->topIsInt()) {
1455          stack->pushReal(ceil(stack->popNum()));
1456        }
1457        break;
1458      case psOpCopy:
1459        stack->copy(stack->popInt());
1460        break;
1461      case psOpCos:
1462        stack->pushReal(cos(stack->popNum() * M_PI / 180.0));
1463        break;
1464      case psOpCvi:
1465        if (!stack->topIsInt()) {
1466          stack->pushInt((int)stack->popNum());
1467        }
1468        break;
1469      case psOpCvr:
1470        if (!stack->topIsReal()) {
1471          stack->pushReal(stack->popNum());
1472        }
1473        break;
1474      case psOpDiv:
1475        r2 = stack->popNum();
1476        r1 = stack->popNum();
1477        stack->pushReal(r1 / r2);
1478        break;
1479      case psOpDup:
1480        stack->copy(1);
1481        break;
1482      case psOpEq:
1483        if (stack->topTwoAreInts()) {
1484          i2 = stack->popInt();
1485          i1 = stack->popInt();
1486          stack->pushBool(i1 == i2);
1487        } else if (stack->topTwoAreNums()) {
1488          r2 = stack->popNum();
1489          r1 = stack->popNum();
1490          stack->pushBool(r1 == r2);
1491        } else {
1492          b2 = stack->popBool();
1493          b1 = stack->popBool();
1494          stack->pushBool(b1 == b2);
1495        }
1496        break;
1497      case psOpExch:
1498        stack->roll(2, 1);
1499        break;
1500      case psOpExp:
1501        r2 = stack->popNum();
1502        r1 = stack->popNum();
1503        stack->pushReal(pow(r1, r2));
1504        break;
1505      case psOpFalse:
1506        stack->pushBool(gFalse);
1507        break;
1508      case psOpFloor:
1509        if (!stack->topIsInt()) {
1510          stack->pushReal(floor(stack->popNum()));
1511        }
1512        break;
1513      case psOpGe:
1514        if (stack->topTwoAreInts()) {
1515          i2 = stack->popInt();
1516          i1 = stack->popInt();
1517          stack->pushBool(i1 >= i2);
1518        } else {
1519          r2 = stack->popNum();
1520          r1 = stack->popNum();
1521          stack->pushBool(r1 >= r2);
1522        }
1523        break;
1524      case psOpGt:
1525        if (stack->topTwoAreInts()) {
1526          i2 = stack->popInt();
1527          i1 = stack->popInt();
1528          stack->pushBool(i1 > i2);
1529        } else {
1530          r2 = stack->popNum();
1531          r1 = stack->popNum();
1532          stack->pushBool(r1 > r2);
1533        }
1534        break;
1535      case psOpIdiv:
1536        i2 = stack->popInt();
1537        i1 = stack->popInt();
1538        stack->pushInt(i1 / i2);
1539        break;
1540      case psOpIndex:
1541        stack->index(stack->popInt());
1542        break;
1543      case psOpLe:
1544        if (stack->topTwoAreInts()) {
1545          i2 = stack->popInt();
1546          i1 = stack->popInt();
1547          stack->pushBool(i1 <= i2);
1548        } else {
1549          r2 = stack->popNum();
1550          r1 = stack->popNum();
1551          stack->pushBool(r1 <= r2);
1552        }
1553        break;
1554      case psOpLn:
1555        stack->pushReal(log(stack->popNum()));
1556        break;
1557      case psOpLog:
1558        stack->pushReal(log10(stack->popNum()));
1559        break;
1560      case psOpLt:
1561        if (stack->topTwoAreInts()) {
1562          i2 = stack->popInt();
1563          i1 = stack->popInt();
1564          stack->pushBool(i1 < i2);
1565        } else {
1566          r2 = stack->popNum();
1567          r1 = stack->popNum();
1568          stack->pushBool(r1 < r2);
1569        }
1570        break;
1571      case psOpMod:
1572        i2 = stack->popInt();
1573        i1 = stack->popInt();
1574        stack->pushInt(i1 % i2);
1575        break;
1576      case psOpMul:
1577        if (stack->topTwoAreInts()) {
1578          i2 = stack->popInt();
1579          i1 = stack->popInt();
1580          //~ should check for out-of-range, and push a real instead
1581          stack->pushInt(i1 * i2);
1582        } else {
1583          r2 = stack->popNum();
1584          r1 = stack->popNum();
1585          stack->pushReal(r1 * r2);
1586        }
1587        break;
1588      case psOpNe:
1589        if (stack->topTwoAreInts()) {
1590          i2 = stack->popInt();
1591          i1 = stack->popInt();
1592          stack->pushBool(i1 != i2);
1593        } else if (stack->topTwoAreNums()) {
1594          r2 = stack->popNum();
1595          r1 = stack->popNum();
1596          stack->pushBool(r1 != r2);
1597        } else {
1598          b2 = stack->popBool();
1599          b1 = stack->popBool();
1600          stack->pushBool(b1 != b2);
1601        }
1602        break;
1603      case psOpNeg:
1604        if (stack->topIsInt()) {
1605          stack->pushInt(-stack->popInt());
1606        } else {
1607          stack->pushReal(-stack->popNum());
1608        }
1609        break;
1610      case psOpNot:
1611        if (stack->topIsInt()) {
1612          stack->pushInt(~stack->popInt());
1613        } else {
1614          stack->pushBool(!stack->popBool());
1615        }
1616        break;
1617      case psOpOr:
1618        if (stack->topTwoAreInts()) {
1619          i2 = stack->popInt();
1620          i1 = stack->popInt();
1621          stack->pushInt(i1 | i2);
1622        } else {
1623          b2 = stack->popBool();
1624          b1 = stack->popBool();
1625          stack->pushBool(b1 || b2);
1626        }
1627        break;
1628      case psOpPop:
1629        stack->pop();
1630        break;
1631      case psOpRoll:
1632        i2 = stack->popInt();
1633        i1 = stack->popInt();
1634        stack->roll(i1, i2);
1635        break;
1636      case psOpRound:
1637        if (!stack->topIsInt()) {
1638          r1 = stack->popNum();
1639          stack->pushReal((r1 >= 0) ? floor(r1 + 0.5) : ceil(r1 - 0.5));
1640        }
1641        break;
1642      case psOpSin:
1643        stack->pushReal(sin(stack->popNum() * M_PI / 180.0));
1644        break;
1645      case psOpSqrt:
1646        stack->pushReal(sqrt(stack->popNum()));
1647        break;
1648      case psOpSub:
1649        if (stack->topTwoAreInts()) {
1650          i2 = stack->popInt();
1651          i1 = stack->popInt();
1652          stack->pushInt(i1 - i2);
1653        } else {
1654          r2 = stack->popNum();
1655          r1 = stack->popNum();
1656          stack->pushReal(r1 - r2);
1657        }
1658        break;
1659      case psOpTrue:
1660        stack->pushBool(gTrue);
1661        break;
1662      case psOpTruncate:
1663        if (!stack->topIsInt()) {
1664          r1 = stack->popNum();
1665          stack->pushReal((r1 >= 0) ? floor(r1) : ceil(r1));
1666        }
1667        break;
1668      case psOpXor:
1669        if (stack->topTwoAreInts()) {
1670          i2 = stack->popInt();
1671          i1 = stack->popInt();
1672          stack->pushInt(i1 ^ i2);
1673        } else {
1674          b2 = stack->popBool();
1675          b1 = stack->popBool();
1676          stack->pushBool(b1 ^ b2);
1677        }
1678        break;
1679      case psOpIf:
1680        b1 = stack->popBool();
1681        if (b1) {
1682          exec(stack, codePtr + 2);
1683        }
1684        codePtr = code[codePtr + 1].blk;
1685        break;
1686      case psOpIfelse:
1687        b1 = stack->popBool();
1688        if (b1) {
1689          exec(stack, codePtr + 2);
1690        } else {
1691          exec(stack, code[codePtr].blk);
1692        }
1693        codePtr = code[codePtr + 1].blk;
1694        break;
1695      case psOpReturn:
1696        return;
1697      }
1698      break;
1699    default:
1700      error(-1, "Internal: bad object in PostScript function code");
1701      break;
1702    }
1703  }
1704}
Note: See TracBrowser for help on using the repository browser.