beta-0.89.2
[luatex.git] / source / libs / poppler / poppler-src / poppler / Function.cc
blob7f359b8eb05807f2856e30b8445f97261970f7e0
1 //========================================================================
2 //
3 // Function.cc
4 //
5 // Copyright 2001-2003 Glyph & Cog, LLC
6 //
7 //========================================================================
9 //========================================================================
11 // Modified under the Poppler project - http://poppler.freedesktop.org
13 // All changes made under the Poppler project to this file are licensed
14 // under GPL version 2 or later
16 // Copyright (C) 2006, 2008-2010, 2013-2015 Albert Astals Cid <aacid@kde.org>
17 // Copyright (C) 2006 Jeff Muizelaar <jeff@infidigm.net>
18 // Copyright (C) 2010 Christian Feuersänger <cfeuersaenger@googlemail.com>
19 // Copyright (C) 2011 Andrea Canciani <ranma42@gmail.com>
20 // Copyright (C) 2012 Thomas Freitag <Thomas.Freitag@alfa.de>
21 // Copyright (C) 2012 Adam Reichold <adamreichold@myopera.com>
22 // Copyright (C) 2013 Fabio D'Urso <fabiodurso@hotmail.it>
24 // To see a description of the changes please see the Changelog file that
25 // came with your tarball or type make ChangeLog if you are building from git
27 //========================================================================
29 #include <config.h>
31 #ifdef USE_GCC_PRAGMAS
32 #pragma implementation
33 #endif
35 #include <stdlib.h>
36 #include <string.h>
37 #include <ctype.h>
38 #include <math.h>
39 #include "goo/gmem.h"
40 #include "goo/gstrtod.h"
41 #include "Object.h"
42 #include "Dict.h"
43 #include "Stream.h"
44 #include "Error.h"
45 #include "Function.h"
47 #ifndef M_PI
48 #define M_PI 3.14159265358979323846
49 #endif
51 //------------------------------------------------------------------------
52 // Function
53 //------------------------------------------------------------------------
55 Function::Function() {
58 Function::~Function() {
61 Function *Function::parse(Object *funcObj) {
62 std::set<int> usedParents;
63 return parse(funcObj, &usedParents);
66 Function *Function::parse(Object *funcObj, std::set<int> *usedParents) {
67 Function *func;
68 Dict *dict;
69 int funcType;
70 Object obj1;
72 if (funcObj->isStream()) {
73 dict = funcObj->streamGetDict();
74 } else if (funcObj->isDict()) {
75 dict = funcObj->getDict();
76 } else if (funcObj->isName("Identity")) {
77 return new IdentityFunction();
78 } else {
79 error(errSyntaxError, -1, "Expected function dictionary or stream");
80 return NULL;
83 if (!dict->lookup("FunctionType", &obj1)->isInt()) {
84 error(errSyntaxError, -1, "Function type is missing or wrong type");
85 obj1.free();
86 return NULL;
88 funcType = obj1.getInt();
89 obj1.free();
91 if (funcType == 0) {
92 func = new SampledFunction(funcObj, dict);
93 } else if (funcType == 2) {
94 func = new ExponentialFunction(funcObj, dict);
95 } else if (funcType == 3) {
96 func = new StitchingFunction(funcObj, dict, usedParents);
97 } else if (funcType == 4) {
98 func = new PostScriptFunction(funcObj, dict);
99 } else {
100 error(errSyntaxError, -1, "Unimplemented function type ({0:d})", funcType);
101 return NULL;
103 if (!func->isOk()) {
104 delete func;
105 return NULL;
108 return func;
111 Function::Function(const Function *func) {
112 m = func->m;
113 n = func->n;
115 memcpy(domain, func->domain, funcMaxInputs * 2 * sizeof(double));
116 memcpy(range, func->range, funcMaxOutputs * 2 * sizeof(double));
118 hasRange = func->hasRange;
121 GBool Function::init(Dict *dict) {
122 Object obj1, obj2;
123 int i;
125 //----- Domain
126 if (!dict->lookup("Domain", &obj1)->isArray()) {
127 error(errSyntaxError, -1, "Function is missing domain");
128 goto err2;
130 m = obj1.arrayGetLength() / 2;
131 if (m > funcMaxInputs) {
132 error(errSyntaxError, -1, "Functions with more than {0:d} inputs are unsupported",
133 funcMaxInputs);
134 goto err2;
136 for (i = 0; i < m; ++i) {
137 obj1.arrayGet(2*i, &obj2);
138 if (!obj2.isNum()) {
139 error(errSyntaxError, -1, "Illegal value in function domain array");
140 goto err1;
142 domain[i][0] = obj2.getNum();
143 obj2.free();
144 obj1.arrayGet(2*i+1, &obj2);
145 if (!obj2.isNum()) {
146 error(errSyntaxError, -1, "Illegal value in function domain array");
147 goto err1;
149 domain[i][1] = obj2.getNum();
150 obj2.free();
152 obj1.free();
154 //----- Range
155 hasRange = gFalse;
156 n = 0;
157 if (dict->lookup("Range", &obj1)->isArray()) {
158 hasRange = gTrue;
159 n = obj1.arrayGetLength() / 2;
160 if (n > funcMaxOutputs) {
161 error(errSyntaxError, -1, "Functions with more than {0:d} outputs are unsupported",
162 funcMaxOutputs);
163 goto err2;
165 for (i = 0; i < n; ++i) {
166 obj1.arrayGet(2*i, &obj2);
167 if (!obj2.isNum()) {
168 error(errSyntaxError, -1, "Illegal value in function range array");
169 goto err1;
171 range[i][0] = obj2.getNum();
172 obj2.free();
173 obj1.arrayGet(2*i+1, &obj2);
174 if (!obj2.isNum()) {
175 error(errSyntaxError, -1, "Illegal value in function range array");
176 goto err1;
178 range[i][1] = obj2.getNum();
179 obj2.free();
182 obj1.free();
184 return gTrue;
186 err1:
187 obj2.free();
188 err2:
189 obj1.free();
190 return gFalse;
193 //------------------------------------------------------------------------
194 // IdentityFunction
195 //------------------------------------------------------------------------
197 IdentityFunction::IdentityFunction() {
198 int i;
200 // fill these in with arbitrary values just in case they get used
201 // somewhere
202 m = funcMaxInputs;
203 n = funcMaxOutputs;
204 for (i = 0; i < funcMaxInputs; ++i) {
205 domain[i][0] = 0;
206 domain[i][1] = 1;
208 hasRange = gFalse;
211 IdentityFunction::~IdentityFunction() {
214 void IdentityFunction::transform(double *in, double *out) {
215 int i;
217 for (i = 0; i < funcMaxOutputs; ++i) {
218 out[i] = in[i];
222 //------------------------------------------------------------------------
223 // SampledFunction
224 //------------------------------------------------------------------------
226 SampledFunction::SampledFunction(Object *funcObj, Dict *dict) {
227 Stream *str;
228 int sampleBits;
229 double sampleMul;
230 Object obj1, obj2;
231 Guint buf, bitMask;
232 int bits;
233 Guint s;
234 double in[funcMaxInputs];
235 int i, j, t, bit, idx;
237 idxOffset = NULL;
238 samples = NULL;
239 sBuf = NULL;
240 ok = gFalse;
242 //----- initialize the generic stuff
243 if (!init(dict)) {
244 goto err1;
246 if (!hasRange) {
247 error(errSyntaxError, -1, "Type 0 function is missing range");
248 goto err1;
250 if (m > sampledFuncMaxInputs) {
251 error(errSyntaxError, -1, "Sampled functions with more than {0:d} inputs are unsupported",
252 sampledFuncMaxInputs);
253 goto err1;
256 //----- buffer
257 sBuf = (double *)gmallocn(1 << m, sizeof(double));
259 //----- get the stream
260 if (!funcObj->isStream()) {
261 error(errSyntaxError, -1, "Type 0 function isn't a stream");
262 goto err1;
264 str = funcObj->getStream();
266 //----- Size
267 if (!dict->lookup("Size", &obj1)->isArray() ||
268 obj1.arrayGetLength() != m) {
269 error(errSyntaxError, -1, "Function has missing or invalid size array");
270 goto err2;
272 for (i = 0; i < m; ++i) {
273 obj1.arrayGet(i, &obj2);
274 if (!obj2.isInt()) {
275 error(errSyntaxError, -1, "Illegal value in function size array");
276 goto err3;
278 sampleSize[i] = obj2.getInt();
279 if (sampleSize[i] <= 0) {
280 error(errSyntaxError, -1, "Illegal non-positive value in function size array");
281 goto err3;
283 obj2.free();
285 obj1.free();
286 idxOffset = (int *)gmallocn(1 << m, sizeof(int));
287 for (i = 0; i < (1<<m); ++i) {
288 idx = 0;
289 for (j = m - 1, t = i; j >= 1; --j, t <<= 1) {
290 if (sampleSize[j] == 1) {
291 bit = 0;
292 } else {
293 bit = (t >> (m - 1)) & 1;
295 idx = (idx + bit) * sampleSize[j-1];
297 if (sampleSize[0] == 1) {
298 bit = 0;
299 } else {
300 bit = (t >> (m - 1)) & 1;
302 idxOffset[i] = (idx + bit) * n;
305 //----- BitsPerSample
306 if (!dict->lookup("BitsPerSample", &obj1)->isInt()) {
307 error(errSyntaxError, -1, "Function has missing or invalid BitsPerSample");
308 goto err2;
310 sampleBits = obj1.getInt();
311 sampleMul = 1.0 / (pow(2.0, (double)sampleBits) - 1);
312 obj1.free();
314 //----- Encode
315 if (dict->lookup("Encode", &obj1)->isArray() &&
316 obj1.arrayGetLength() == 2*m) {
317 for (i = 0; i < m; ++i) {
318 obj1.arrayGet(2*i, &obj2);
319 if (!obj2.isNum()) {
320 error(errSyntaxError, -1, "Illegal value in function encode array");
321 goto err3;
323 encode[i][0] = obj2.getNum();
324 obj2.free();
325 obj1.arrayGet(2*i+1, &obj2);
326 if (!obj2.isNum()) {
327 error(errSyntaxError, -1, "Illegal value in function encode array");
328 goto err3;
330 encode[i][1] = obj2.getNum();
331 obj2.free();
333 } else {
334 for (i = 0; i < m; ++i) {
335 encode[i][0] = 0;
336 encode[i][1] = sampleSize[i] - 1;
339 obj1.free();
340 for (i = 0; i < m; ++i) {
341 inputMul[i] = (encode[i][1] - encode[i][0]) /
342 (domain[i][1] - domain[i][0]);
345 //----- Decode
346 if (dict->lookup("Decode", &obj1)->isArray() &&
347 obj1.arrayGetLength() == 2*n) {
348 for (i = 0; i < n; ++i) {
349 obj1.arrayGet(2*i, &obj2);
350 if (!obj2.isNum()) {
351 error(errSyntaxError, -1, "Illegal value in function decode array");
352 goto err3;
354 decode[i][0] = obj2.getNum();
355 obj2.free();
356 obj1.arrayGet(2*i+1, &obj2);
357 if (!obj2.isNum()) {
358 error(errSyntaxError, -1, "Illegal value in function decode array");
359 goto err3;
361 decode[i][1] = obj2.getNum();
362 obj2.free();
364 } else {
365 for (i = 0; i < n; ++i) {
366 decode[i][0] = range[i][0];
367 decode[i][1] = range[i][1];
370 obj1.free();
372 //----- samples
373 nSamples = n;
374 for (i = 0; i < m; ++i)
375 nSamples *= sampleSize[i];
376 samples = (double *)gmallocn(nSamples, sizeof(double));
377 buf = 0;
378 bits = 0;
379 bitMask = (1 << sampleBits) - 1;
380 str->reset();
381 for (i = 0; i < nSamples; ++i) {
382 if (sampleBits == 8) {
383 s = str->getChar();
384 } else if (sampleBits == 16) {
385 s = str->getChar();
386 s = (s << 8) + str->getChar();
387 } else if (sampleBits == 32) {
388 s = str->getChar();
389 s = (s << 8) + str->getChar();
390 s = (s << 8) + str->getChar();
391 s = (s << 8) + str->getChar();
392 } else {
393 while (bits < sampleBits) {
394 buf = (buf << 8) | (str->getChar() & 0xff);
395 bits += 8;
397 s = (buf >> (bits - sampleBits)) & bitMask;
398 bits -= sampleBits;
400 samples[i] = (double)s * sampleMul;
402 str->close();
404 // set up the cache
405 for (i = 0; i < m; ++i) {
406 in[i] = domain[i][0];
407 cacheIn[i] = in[i] - 1;
409 transform(in, cacheOut);
411 ok = gTrue;
412 return;
414 err3:
415 obj2.free();
416 err2:
417 obj1.free();
418 err1:
419 return;
422 SampledFunction::~SampledFunction() {
423 if (idxOffset) {
424 gfree(idxOffset);
426 if (samples) {
427 gfree(samples);
429 if (sBuf) {
430 gfree(sBuf);
434 SampledFunction::SampledFunction(const SampledFunction *func) : Function(func) {
435 memcpy(sampleSize, func->sampleSize, funcMaxInputs * sizeof(int));
437 memcpy(encode, func->encode, funcMaxInputs * 2 * sizeof(double));
438 memcpy(decode, func->decode, funcMaxOutputs * 2 * sizeof(double));
440 memcpy(inputMul, func->inputMul, funcMaxInputs * sizeof(double));
442 nSamples = func->nSamples;
444 idxOffset = (int *)gmallocn(1 << m, sizeof(int));
445 memcpy(idxOffset, func->idxOffset, (1 << m) * (int)sizeof(int));
447 samples = (double *)gmallocn(nSamples, sizeof(double));
448 memcpy(samples, func->samples, nSamples * sizeof(double));
450 sBuf = (double *)gmallocn(1 << m, sizeof(double));
452 memcpy(cacheIn, func->cacheIn, funcMaxInputs * sizeof(double));
453 memcpy(cacheOut, func->cacheOut, funcMaxOutputs * sizeof(double));
455 ok = func->ok;
458 void SampledFunction::transform(double *in, double *out) {
459 double x;
460 int e[funcMaxInputs];
461 double efrac0[funcMaxInputs];
462 double efrac1[funcMaxInputs];
463 int i, j, k, idx0, t;
465 // check the cache
466 for (i = 0; i < m; ++i) {
467 if (in[i] != cacheIn[i]) {
468 break;
471 if (i == m) {
472 for (i = 0; i < n; ++i) {
473 out[i] = cacheOut[i];
475 return;
478 // map input values into sample array
479 for (i = 0; i < m; ++i) {
480 x = (in[i] - domain[i][0]) * inputMul[i] + encode[i][0];
481 if (x < 0 || x != x) { // x!=x is a more portable version of isnan(x)
482 x = 0;
483 } else if (x > sampleSize[i] - 1) {
484 x = sampleSize[i] - 1;
486 e[i] = (int)x;
487 if (e[i] == sampleSize[i] - 1 && sampleSize[i] > 1) {
488 // this happens if in[i] = domain[i][1]
489 e[i] = sampleSize[i] - 2;
491 efrac1[i] = x - e[i];
492 efrac0[i] = 1 - efrac1[i];
495 // compute index for the first sample to be used
496 idx0 = 0;
497 for (k = m - 1; k >= 1; --k) {
498 idx0 = (idx0 + e[k]) * sampleSize[k-1];
500 idx0 = (idx0 + e[0]) * n;
502 // for each output, do m-linear interpolation
503 for (i = 0; i < n; ++i) {
505 // pull 2^m values out of the sample array
506 for (j = 0; j < (1<<m); ++j) {
507 int idx = idx0 + idxOffset[j] + i;
508 if (likely(idx >= 0 && idx < nSamples)) {
509 sBuf[j] = samples[idx];
510 } else {
511 sBuf[j] = 0; // TODO Investigate if this is what Adobe does
515 // do m sets of interpolations
516 for (j = 0, t = (1<<m); j < m; ++j, t >>= 1) {
517 for (k = 0; k < t; k += 2) {
518 sBuf[k >> 1] = efrac0[j] * sBuf[k] + efrac1[j] * sBuf[k+1];
522 // map output value to range
523 out[i] = sBuf[0] * (decode[i][1] - decode[i][0]) + decode[i][0];
524 if (out[i] < range[i][0]) {
525 out[i] = range[i][0];
526 } else if (out[i] > range[i][1]) {
527 out[i] = range[i][1];
531 // save current result in the cache
532 for (i = 0; i < m; ++i) {
533 cacheIn[i] = in[i];
535 for (i = 0; i < n; ++i) {
536 cacheOut[i] = out[i];
540 GBool SampledFunction::hasDifferentResultSet(Function *func) {
541 if (func->getType() == 0) {
542 SampledFunction *compTo = (SampledFunction *) func;
543 if (compTo->getSampleNumber() != nSamples)
544 return gTrue;
545 double *compSamples = compTo->getSamples();
546 for (int i = 0; i < nSamples; i++) {
547 if (samples[i] != compSamples[i])
548 return gTrue;
551 return gFalse;
554 //------------------------------------------------------------------------
555 // ExponentialFunction
556 //------------------------------------------------------------------------
558 ExponentialFunction::ExponentialFunction(Object *funcObj, Dict *dict) {
559 Object obj1, obj2;
560 int i;
562 ok = gFalse;
564 //----- initialize the generic stuff
565 if (!init(dict)) {
566 goto err1;
568 if (m != 1) {
569 error(errSyntaxError, -1, "Exponential function with more than one input");
570 goto err1;
573 //----- C0
574 if (dict->lookup("C0", &obj1)->isArray()) {
575 if (hasRange && obj1.arrayGetLength() != n) {
576 error(errSyntaxError, -1, "Function's C0 array is wrong length");
577 goto err2;
579 n = obj1.arrayGetLength();
580 if (unlikely(n > funcMaxOutputs)) {
581 error(errSyntaxError, -1, "Function's C0 array is wrong length");
582 n = funcMaxOutputs;
584 for (i = 0; i < n; ++i) {
585 obj1.arrayGet(i, &obj2);
586 if (!obj2.isNum()) {
587 error(errSyntaxError, -1, "Illegal value in function C0 array");
588 goto err3;
590 c0[i] = obj2.getNum();
591 obj2.free();
593 } else {
594 if (hasRange && n != 1) {
595 error(errSyntaxError, -1, "Function's C0 array is wrong length");
596 goto err2;
598 n = 1;
599 c0[0] = 0;
601 obj1.free();
603 //----- C1
604 if (dict->lookup("C1", &obj1)->isArray()) {
605 if (obj1.arrayGetLength() != n) {
606 error(errSyntaxError, -1, "Function's C1 array is wrong length");
607 goto err2;
609 for (i = 0; i < n; ++i) {
610 obj1.arrayGet(i, &obj2);
611 if (!obj2.isNum()) {
612 error(errSyntaxError, -1, "Illegal value in function C1 array");
613 goto err3;
615 c1[i] = obj2.getNum();
616 obj2.free();
618 } else {
619 if (n != 1) {
620 error(errSyntaxError, -1, "Function's C1 array is wrong length");
621 goto err2;
623 c1[0] = 1;
625 obj1.free();
627 //----- N (exponent)
628 if (!dict->lookup("N", &obj1)->isNum()) {
629 error(errSyntaxError, -1, "Function has missing or invalid N");
630 goto err2;
632 e = obj1.getNum();
633 obj1.free();
635 isLinear = fabs(e-1.) < 1e-10;
636 ok = gTrue;
637 return;
639 err3:
640 obj2.free();
641 err2:
642 obj1.free();
643 err1:
644 return;
647 ExponentialFunction::~ExponentialFunction() {
650 ExponentialFunction::ExponentialFunction(const ExponentialFunction *func) : Function(func) {
651 memcpy(c0, func->c0, funcMaxOutputs * sizeof(double));
652 memcpy(c1, func->c1, funcMaxOutputs * sizeof(double));
654 e = func->e;
655 isLinear = func->isLinear;
656 ok = func->ok;
659 void ExponentialFunction::transform(double *in, double *out) {
660 double x;
661 int i;
663 if (in[0] < domain[0][0]) {
664 x = domain[0][0];
665 } else if (in[0] > domain[0][1]) {
666 x = domain[0][1];
667 } else {
668 x = in[0];
670 for (i = 0; i < n; ++i) {
671 out[i] = c0[i] + (isLinear ? x : pow(x, e)) * (c1[i] - c0[i]);
672 if (hasRange) {
673 if (out[i] < range[i][0]) {
674 out[i] = range[i][0];
675 } else if (out[i] > range[i][1]) {
676 out[i] = range[i][1];
680 return;
683 //------------------------------------------------------------------------
684 // StitchingFunction
685 //------------------------------------------------------------------------
687 StitchingFunction::StitchingFunction(Object *funcObj, Dict *dict, std::set<int> *usedParents) {
688 Object obj1, obj2;
689 int i;
691 ok = gFalse;
692 funcs = NULL;
693 bounds = NULL;
694 encode = NULL;
695 scale = NULL;
697 //----- initialize the generic stuff
698 if (!init(dict)) {
699 goto err1;
701 if (m != 1) {
702 error(errSyntaxError, -1, "Stitching function with more than one input");
703 goto err1;
706 //----- Functions
707 if (!dict->lookup("Functions", &obj1)->isArray()) {
708 error(errSyntaxError, -1, "Missing 'Functions' entry in stitching function");
709 goto err1;
711 k = obj1.arrayGetLength();
712 funcs = (Function **)gmallocn(k, sizeof(Function *));
713 bounds = (double *)gmallocn(k + 1, sizeof(double));
714 encode = (double *)gmallocn(2 * k, sizeof(double));
715 scale = (double *)gmallocn(k, sizeof(double));
716 for (i = 0; i < k; ++i) {
717 funcs[i] = NULL;
719 for (i = 0; i < k; ++i) {
720 std::set<int> usedParentsAux = *usedParents;
721 obj1.arrayGetNF(i, &obj2);
722 if (obj2.isRef()) {
723 const Ref ref = obj2.getRef();
724 if (usedParentsAux.find(ref.num) == usedParentsAux.end()) {
725 usedParentsAux.insert(ref.num);
726 obj2.free();
727 obj1.arrayGet(i, &obj2);
728 } else {
729 goto err2;
732 if (!(funcs[i] = Function::parse(&obj2, &usedParentsAux))) {
733 goto err2;
735 if (funcs[i]->getInputSize() != 1 ||
736 (i > 0 && funcs[i]->getOutputSize() != funcs[0]->getOutputSize())) {
737 error(errSyntaxError, -1,
738 "Incompatible subfunctions in stitching function");
739 goto err2;
741 obj2.free();
743 obj1.free();
745 //----- Bounds
746 if (!dict->lookup("Bounds", &obj1)->isArray() ||
747 obj1.arrayGetLength() != k - 1) {
748 error(errSyntaxError, -1, "Missing or invalid 'Bounds' entry in stitching function");
749 goto err1;
751 bounds[0] = domain[0][0];
752 for (i = 1; i < k; ++i) {
753 if (!obj1.arrayGet(i - 1, &obj2)->isNum()) {
754 error(errSyntaxError, -1, "Invalid type in 'Bounds' array in stitching function");
755 goto err2;
757 bounds[i] = obj2.getNum();
758 obj2.free();
760 bounds[k] = domain[0][1];
761 obj1.free();
763 //----- Encode
764 if (!dict->lookup("Encode", &obj1)->isArray() ||
765 obj1.arrayGetLength() != 2 * k) {
766 error(errSyntaxError, -1, "Missing or invalid 'Encode' entry in stitching function");
767 goto err1;
769 for (i = 0; i < 2 * k; ++i) {
770 if (!obj1.arrayGet(i, &obj2)->isNum()) {
771 error(errSyntaxError, -1, "Invalid type in 'Encode' array in stitching function");
772 goto err2;
774 encode[i] = obj2.getNum();
775 obj2.free();
777 obj1.free();
779 //----- pre-compute the scale factors
780 for (i = 0; i < k; ++i) {
781 if (bounds[i] == bounds[i+1]) {
782 // avoid a divide-by-zero -- in this situation, function i will
783 // never be used anyway
784 scale[i] = 0;
785 } else {
786 scale[i] = (encode[2*i+1] - encode[2*i]) / (bounds[i+1] - bounds[i]);
790 n = funcs[0]->getOutputSize();
791 ok = gTrue;
792 return;
794 err2:
795 obj2.free();
796 err1:
797 obj1.free();
800 StitchingFunction::StitchingFunction(const StitchingFunction *func) : Function(func) {
801 k = func->k;
803 funcs = (Function **)gmallocn(k, sizeof(Function *));
804 for (int i = 0; i < k; ++i) {
805 funcs[i] = func->funcs[i]->copy();
808 bounds = (double *)gmallocn(k + 1, sizeof(double));
809 memcpy(bounds, func->bounds, (k + 1) * sizeof(double));
811 encode = (double *)gmallocn(2 * k, sizeof(double));
812 memcpy(encode, func->encode, 2 * k * sizeof(double));
814 scale = (double *)gmallocn(k, sizeof(double));
815 memcpy(scale, func->scale, k * sizeof(double));
817 ok = func->ok;
820 StitchingFunction::~StitchingFunction() {
821 int i;
823 if (funcs) {
824 for (i = 0; i < k; ++i) {
825 if (funcs[i]) {
826 delete funcs[i];
830 gfree(funcs);
831 gfree(bounds);
832 gfree(encode);
833 gfree(scale);
836 void StitchingFunction::transform(double *in, double *out) {
837 double x;
838 int i;
840 if (in[0] < domain[0][0]) {
841 x = domain[0][0];
842 } else if (in[0] > domain[0][1]) {
843 x = domain[0][1];
844 } else {
845 x = in[0];
847 for (i = 0; i < k - 1; ++i) {
848 if (x < bounds[i+1]) {
849 break;
852 x = encode[2*i] + (x - bounds[i]) * scale[i];
853 funcs[i]->transform(&x, out);
856 //------------------------------------------------------------------------
857 // PostScriptFunction
858 //------------------------------------------------------------------------
860 enum PSOp {
861 psOpAbs,
862 psOpAdd,
863 psOpAnd,
864 psOpAtan,
865 psOpBitshift,
866 psOpCeiling,
867 psOpCopy,
868 psOpCos,
869 psOpCvi,
870 psOpCvr,
871 psOpDiv,
872 psOpDup,
873 psOpEq,
874 psOpExch,
875 psOpExp,
876 psOpFalse,
877 psOpFloor,
878 psOpGe,
879 psOpGt,
880 psOpIdiv,
881 psOpIndex,
882 psOpLe,
883 psOpLn,
884 psOpLog,
885 psOpLt,
886 psOpMod,
887 psOpMul,
888 psOpNe,
889 psOpNeg,
890 psOpNot,
891 psOpOr,
892 psOpPop,
893 psOpRoll,
894 psOpRound,
895 psOpSin,
896 psOpSqrt,
897 psOpSub,
898 psOpTrue,
899 psOpTruncate,
900 psOpXor,
901 psOpIf,
902 psOpIfelse,
903 psOpReturn
906 // Note: 'if' and 'ifelse' are parsed separately.
907 // The rest are listed here in alphabetical order.
908 // The index in this table is equivalent to the entry in PSOp.
909 static const char *psOpNames[] = {
910 "abs",
911 "add",
912 "and",
913 "atan",
914 "bitshift",
915 "ceiling",
916 "copy",
917 "cos",
918 "cvi",
919 "cvr",
920 "div",
921 "dup",
922 "eq",
923 "exch",
924 "exp",
925 "false",
926 "floor",
927 "ge",
928 "gt",
929 "idiv",
930 "index",
931 "le",
932 "ln",
933 "log",
934 "lt",
935 "mod",
936 "mul",
937 "ne",
938 "neg",
939 "not",
940 "or",
941 "pop",
942 "roll",
943 "round",
944 "sin",
945 "sqrt",
946 "sub",
947 "true",
948 "truncate",
949 "xor"
952 #define nPSOps (sizeof(psOpNames) / sizeof(char *))
954 enum PSObjectType {
955 psBool,
956 psInt,
957 psReal,
958 psOperator,
959 psBlock
962 // In the code array, 'if'/'ifelse' operators take up three slots
963 // plus space for the code in the subclause(s).
965 // +---------------------------------+
966 // | psOperator: psOpIf / psOpIfelse |
967 // +---------------------------------+
968 // | psBlock: ptr=<A> |
969 // +---------------------------------+
970 // | psBlock: ptr=<B> |
971 // +---------------------------------+
972 // | if clause |
973 // | ... |
974 // | psOperator: psOpReturn |
975 // +---------------------------------+
976 // <A> | else clause |
977 // | ... |
978 // | psOperator: psOpReturn |
979 // +---------------------------------+
980 // <B> | ... |
982 // For 'if', pointer <A> is present in the code stream but unused.
984 struct PSObject {
985 PSObjectType type;
986 union {
987 GBool booln; // boolean (stack only)
988 int intg; // integer (stack and code)
989 double real; // real (stack and code)
990 PSOp op; // operator (code only)
991 int blk; // if/ifelse block pointer (code only)
995 #define psStackSize 100
997 class PSStack {
998 public:
1000 PSStack() {sp = psStackSize; }
1001 void clear() { sp = psStackSize; }
1002 void pushBool(GBool booln)
1004 if (checkOverflow()) {
1005 stack[--sp].type = psBool;
1006 stack[sp].booln = booln;
1009 void pushInt(int intg)
1011 if (checkOverflow()) {
1012 stack[--sp].type = psInt;
1013 stack[sp].intg = intg;
1016 void pushReal(double real)
1018 if (checkOverflow()) {
1019 stack[--sp].type = psReal;
1020 stack[sp].real = real;
1023 GBool popBool()
1025 if (checkUnderflow() && checkType(psBool, psBool)) {
1026 return stack[sp++].booln;
1028 return gFalse;
1030 int popInt()
1032 if (checkUnderflow() && checkType(psInt, psInt)) {
1033 return stack[sp++].intg;
1035 return 0;
1037 double popNum()
1039 double ret;
1041 if (checkUnderflow() && checkType(psInt, psReal)) {
1042 ret = (stack[sp].type == psInt) ? (double)stack[sp].intg : stack[sp].real;
1043 ++sp;
1044 return ret;
1046 return 0;
1048 GBool empty() { return sp == psStackSize; }
1049 GBool topIsInt() { return sp < psStackSize && stack[sp].type == psInt; }
1050 GBool topTwoAreInts()
1051 { return sp < psStackSize - 1 &&
1052 stack[sp].type == psInt &&
1053 stack[sp+1].type == psInt; }
1054 GBool topIsReal() { return sp < psStackSize && stack[sp].type == psReal; }
1055 GBool topTwoAreNums()
1056 { return sp < psStackSize - 1 &&
1057 (stack[sp].type == psInt || stack[sp].type == psReal) &&
1058 (stack[sp+1].type == psInt || stack[sp+1].type == psReal); }
1059 void copy(int n);
1060 void roll(int n, int j);
1061 void index(int i)
1063 if (!checkOverflow()) {
1064 return;
1066 --sp;
1067 if (unlikely(sp + i + 1 >= psStackSize)) {
1068 error(errSyntaxError, -1, "Stack underflow in PostScript function");
1069 return;
1071 if (unlikely(sp + i + 1 < 0)) {
1072 error(errSyntaxError, -1, "Stack overflow in PostScript function");
1073 return;
1075 stack[sp] = stack[sp + 1 + i];
1077 void pop()
1079 if (!checkUnderflow()) {
1080 return;
1082 ++sp;
1085 private:
1087 GBool checkOverflow(int n = 1)
1089 if (sp - n < 0) {
1090 error(errSyntaxError, -1, "Stack overflow in PostScript function");
1091 return gFalse;
1093 return gTrue;
1095 GBool checkUnderflow()
1097 if (sp == psStackSize) {
1098 error(errSyntaxError, -1, "Stack underflow in PostScript function");
1099 return gFalse;
1101 return gTrue;
1103 GBool checkType(PSObjectType t1, PSObjectType t2)
1105 if (stack[sp].type != t1 && stack[sp].type != t2) {
1106 error(errSyntaxError, -1, "Type mismatch in PostScript function");
1107 return gFalse;
1109 return gTrue;
1111 PSObject stack[psStackSize];
1112 int sp;
1116 void PSStack::copy(int n) {
1117 int i;
1119 if (sp + n > psStackSize) {
1120 error(errSyntaxError, -1, "Stack underflow in PostScript function");
1121 return;
1123 if (unlikely(sp - n > psStackSize)) {
1124 error(errSyntaxError, -1, "Stack underflow in PostScript function");
1125 return;
1127 if (!checkOverflow(n)) {
1128 return;
1130 for (i = sp + n - 1; i >= sp; --i) {
1131 stack[i - n] = stack[i];
1133 sp -= n;
1136 void PSStack::roll(int n, int j) {
1137 PSObject obj;
1138 int i, k;
1140 if (unlikely(n == 0)) {
1141 return;
1143 if (j >= 0) {
1144 j %= n;
1145 } else {
1146 j = -j % n;
1147 if (j != 0) {
1148 j = n - j;
1151 if (n <= 0 || j == 0 || n > psStackSize || sp + n > psStackSize) {
1152 return;
1154 if (j <= n / 2) {
1155 for (i = 0; i < j; ++i) {
1156 obj = stack[sp];
1157 for (k = sp; k < sp + n - 1; ++k) {
1158 stack[k] = stack[k+1];
1160 stack[sp + n - 1] = obj;
1162 } else {
1163 j = n - j;
1164 for (i = 0; i < j; ++i) {
1165 obj = stack[sp + n - 1];
1166 for (k = sp + n - 1; k > sp; --k) {
1167 stack[k] = stack[k-1];
1169 stack[sp] = obj;
1174 PostScriptFunction::PostScriptFunction(Object *funcObj, Dict *dict) {
1175 Stream *str;
1176 int codePtr;
1177 GooString *tok;
1178 double in[funcMaxInputs];
1179 int i;
1181 code = NULL;
1182 codeString = NULL;
1183 codeSize = 0;
1184 ok = gFalse;
1186 //----- initialize the generic stuff
1187 if (!init(dict)) {
1188 goto err1;
1190 if (!hasRange) {
1191 error(errSyntaxError, -1, "Type 4 function is missing range");
1192 goto err1;
1195 //----- get the stream
1196 if (!funcObj->isStream()) {
1197 error(errSyntaxError, -1, "Type 4 function isn't a stream");
1198 goto err1;
1200 str = funcObj->getStream();
1202 //----- parse the function
1203 codeString = new GooString();
1204 str->reset();
1205 if (!(tok = getToken(str)) || tok->cmp("{")) {
1206 error(errSyntaxError, -1, "Expected '{{' at start of PostScript function");
1207 if (tok) {
1208 delete tok;
1210 goto err1;
1212 delete tok;
1213 codePtr = 0;
1214 if (!parseCode(str, &codePtr)) {
1215 goto err2;
1217 str->close();
1219 //----- set up the cache
1220 for (i = 0; i < m; ++i) {
1221 in[i] = domain[i][0];
1222 cacheIn[i] = in[i] - 1;
1224 transform(in, cacheOut);
1226 ok = gTrue;
1228 err2:
1229 str->close();
1230 err1:
1231 return;
1234 PostScriptFunction::PostScriptFunction(const PostScriptFunction *func) : Function(func) {
1235 codeSize = func->codeSize;
1237 code = (PSObject *)gmallocn(codeSize, sizeof(PSObject));
1238 memcpy(code, func->code, codeSize * sizeof(PSObject));
1240 codeString = func->codeString->copy();
1242 memcpy(cacheIn, func->cacheIn, funcMaxInputs * sizeof(double));
1243 memcpy(cacheOut, func->cacheOut, funcMaxOutputs * sizeof(double));
1245 ok = func->ok;
1248 PostScriptFunction::~PostScriptFunction() {
1249 gfree(code);
1250 delete codeString;
1253 void PostScriptFunction::transform(double *in, double *out) {
1254 PSStack stack;
1255 int i;
1257 // check the cache
1258 for (i = 0; i < m; ++i) {
1259 if (in[i] != cacheIn[i]) {
1260 break;
1263 if (i == m) {
1264 for (i = 0; i < n; ++i) {
1265 out[i] = cacheOut[i];
1267 return;
1270 for (i = 0; i < m; ++i) {
1271 //~ may need to check for integers here
1272 stack.pushReal(in[i]);
1274 exec(&stack, 0);
1275 for (i = n - 1; i >= 0; --i) {
1276 out[i] = stack.popNum();
1277 if (out[i] < range[i][0]) {
1278 out[i] = range[i][0];
1279 } else if (out[i] > range[i][1]) {
1280 out[i] = range[i][1];
1283 stack.clear();
1285 // if (!stack->empty()) {
1286 // error(errSyntaxWarning, -1,
1287 // "Extra values on stack at end of PostScript function");
1288 // }
1290 // save current result in the cache
1291 for (i = 0; i < m; ++i) {
1292 cacheIn[i] = in[i];
1294 for (i = 0; i < n; ++i) {
1295 cacheOut[i] = out[i];
1299 GBool PostScriptFunction::parseCode(Stream *str, int *codePtr) {
1300 GooString *tok;
1301 char *p;
1302 GBool isReal;
1303 int opPtr, elsePtr;
1304 int a, b, mid, cmp;
1306 while (1) {
1307 if (!(tok = getToken(str))) {
1308 error(errSyntaxError, -1, "Unexpected end of PostScript function stream");
1309 return gFalse;
1311 p = tok->getCString();
1312 if (isdigit(*p) || *p == '.' || *p == '-') {
1313 isReal = gFalse;
1314 for (; *p; ++p) {
1315 if (*p == '.') {
1316 isReal = gTrue;
1317 break;
1320 resizeCode(*codePtr);
1321 if (isReal) {
1322 code[*codePtr].type = psReal;
1323 code[*codePtr].real = gatof(tok->getCString());
1324 } else {
1325 code[*codePtr].type = psInt;
1326 code[*codePtr].intg = atoi(tok->getCString());
1328 ++*codePtr;
1329 delete tok;
1330 } else if (!tok->cmp("{")) {
1331 delete tok;
1332 opPtr = *codePtr;
1333 *codePtr += 3;
1334 resizeCode(opPtr + 2);
1335 if (!parseCode(str, codePtr)) {
1336 return gFalse;
1338 if (!(tok = getToken(str))) {
1339 error(errSyntaxError, -1, "Unexpected end of PostScript function stream");
1340 return gFalse;
1342 if (!tok->cmp("{")) {
1343 elsePtr = *codePtr;
1344 if (!parseCode(str, codePtr)) {
1345 return gFalse;
1347 delete tok;
1348 if (!(tok = getToken(str))) {
1349 error(errSyntaxError, -1, "Unexpected end of PostScript function stream");
1350 return gFalse;
1352 } else {
1353 elsePtr = -1;
1355 if (!tok->cmp("if")) {
1356 if (elsePtr >= 0) {
1357 error(errSyntaxError, -1,
1358 "Got 'if' operator with two blocks in PostScript function");
1359 return gFalse;
1361 code[opPtr].type = psOperator;
1362 code[opPtr].op = psOpIf;
1363 code[opPtr+2].type = psBlock;
1364 code[opPtr+2].blk = *codePtr;
1365 } else if (!tok->cmp("ifelse")) {
1366 if (elsePtr < 0) {
1367 error(errSyntaxError, -1,
1368 "Got 'ifelse' operator with one block in PostScript function");
1369 return gFalse;
1371 code[opPtr].type = psOperator;
1372 code[opPtr].op = psOpIfelse;
1373 code[opPtr+1].type = psBlock;
1374 code[opPtr+1].blk = elsePtr;
1375 code[opPtr+2].type = psBlock;
1376 code[opPtr+2].blk = *codePtr;
1377 } else {
1378 error(errSyntaxError, -1,
1379 "Expected if/ifelse operator in PostScript function");
1380 delete tok;
1381 return gFalse;
1383 delete tok;
1384 } else if (!tok->cmp("}")) {
1385 delete tok;
1386 resizeCode(*codePtr);
1387 code[*codePtr].type = psOperator;
1388 code[*codePtr].op = psOpReturn;
1389 ++*codePtr;
1390 break;
1391 } else {
1392 a = -1;
1393 b = nPSOps;
1394 cmp = 0; // make gcc happy
1395 // invariant: psOpNames[a] < tok < psOpNames[b]
1396 while (b - a > 1) {
1397 mid = (a + b) / 2;
1398 cmp = tok->cmp(psOpNames[mid]);
1399 if (cmp > 0) {
1400 a = mid;
1401 } else if (cmp < 0) {
1402 b = mid;
1403 } else {
1404 a = b = mid;
1407 if (cmp != 0) {
1408 error(errSyntaxError, -1,
1409 "Unknown operator '{0:t}' in PostScript function",
1410 tok);
1411 delete tok;
1412 return gFalse;
1414 delete tok;
1415 resizeCode(*codePtr);
1416 code[*codePtr].type = psOperator;
1417 code[*codePtr].op = (PSOp)a;
1418 ++*codePtr;
1421 return gTrue;
1424 GooString *PostScriptFunction::getToken(Stream *str) {
1425 GooString *s;
1426 int c;
1427 GBool comment;
1429 s = new GooString();
1430 comment = gFalse;
1431 while (1) {
1432 if ((c = str->getChar()) == EOF) {
1433 break;
1435 codeString->append(c);
1436 if (comment) {
1437 if (c == '\x0a' || c == '\x0d') {
1438 comment = gFalse;
1440 } else if (c == '%') {
1441 comment = gTrue;
1442 } else if (!isspace(c)) {
1443 break;
1446 if (c == '{' || c == '}') {
1447 s->append((char)c);
1448 } else if (isdigit(c) || c == '.' || c == '-') {
1449 while (1) {
1450 s->append((char)c);
1451 c = str->lookChar();
1452 if (c == EOF || !(isdigit(c) || c == '.' || c == '-')) {
1453 break;
1455 str->getChar();
1456 codeString->append(c);
1458 } else {
1459 while (1) {
1460 s->append((char)c);
1461 c = str->lookChar();
1462 if (c == EOF || !isalnum(c)) {
1463 break;
1465 str->getChar();
1466 codeString->append(c);
1469 return s;
1472 void PostScriptFunction::resizeCode(int newSize) {
1473 if (newSize >= codeSize) {
1474 codeSize += 64;
1475 code = (PSObject *)greallocn(code, codeSize, sizeof(PSObject));
1479 void PostScriptFunction::exec(PSStack *stack, int codePtr) {
1480 int i1, i2;
1481 double r1, r2, result;
1482 GBool b1, b2;
1484 while (1) {
1485 switch (code[codePtr].type) {
1486 case psInt:
1487 stack->pushInt(code[codePtr++].intg);
1488 break;
1489 case psReal:
1490 stack->pushReal(code[codePtr++].real);
1491 break;
1492 case psOperator:
1493 switch (code[codePtr++].op) {
1494 case psOpAbs:
1495 if (stack->topIsInt()) {
1496 stack->pushInt(abs(stack->popInt()));
1497 } else {
1498 stack->pushReal(fabs(stack->popNum()));
1500 break;
1501 case psOpAdd:
1502 if (stack->topTwoAreInts()) {
1503 i2 = stack->popInt();
1504 i1 = stack->popInt();
1505 stack->pushInt(i1 + i2);
1506 } else {
1507 r2 = stack->popNum();
1508 r1 = stack->popNum();
1509 stack->pushReal(r1 + r2);
1511 break;
1512 case psOpAnd:
1513 if (stack->topTwoAreInts()) {
1514 i2 = stack->popInt();
1515 i1 = stack->popInt();
1516 stack->pushInt(i1 & i2);
1517 } else {
1518 b2 = stack->popBool();
1519 b1 = stack->popBool();
1520 stack->pushBool(b1 && b2);
1522 break;
1523 case psOpAtan:
1524 r2 = stack->popNum();
1525 r1 = stack->popNum();
1526 result = atan2(r1, r2) * 180.0 / M_PI;
1527 if (result < 0) result += 360.0;
1528 stack->pushReal(result);
1529 break;
1530 case psOpBitshift:
1531 i2 = stack->popInt();
1532 i1 = stack->popInt();
1533 if (i2 > 0) {
1534 stack->pushInt(i1 << i2);
1535 } else if (i2 < 0) {
1536 stack->pushInt((int)((Guint)i1 >> -i2));
1537 } else {
1538 stack->pushInt(i1);
1540 break;
1541 case psOpCeiling:
1542 if (!stack->topIsInt()) {
1543 stack->pushReal(ceil(stack->popNum()));
1545 break;
1546 case psOpCopy:
1547 stack->copy(stack->popInt());
1548 break;
1549 case psOpCos:
1550 stack->pushReal(cos(stack->popNum() * M_PI / 180.0));
1551 break;
1552 case psOpCvi:
1553 if (!stack->topIsInt()) {
1554 stack->pushInt((int)stack->popNum());
1556 break;
1557 case psOpCvr:
1558 if (!stack->topIsReal()) {
1559 stack->pushReal(stack->popNum());
1561 break;
1562 case psOpDiv:
1563 r2 = stack->popNum();
1564 r1 = stack->popNum();
1565 stack->pushReal(r1 / r2);
1566 break;
1567 case psOpDup:
1568 stack->copy(1);
1569 break;
1570 case psOpEq:
1571 if (stack->topTwoAreInts()) {
1572 i2 = stack->popInt();
1573 i1 = stack->popInt();
1574 stack->pushBool(i1 == i2);
1575 } else if (stack->topTwoAreNums()) {
1576 r2 = stack->popNum();
1577 r1 = stack->popNum();
1578 stack->pushBool(r1 == r2);
1579 } else {
1580 b2 = stack->popBool();
1581 b1 = stack->popBool();
1582 stack->pushBool(b1 == b2);
1584 break;
1585 case psOpExch:
1586 stack->roll(2, 1);
1587 break;
1588 case psOpExp:
1589 r2 = stack->popNum();
1590 r1 = stack->popNum();
1591 stack->pushReal(pow(r1, r2));
1592 break;
1593 case psOpFalse:
1594 stack->pushBool(gFalse);
1595 break;
1596 case psOpFloor:
1597 if (!stack->topIsInt()) {
1598 stack->pushReal(floor(stack->popNum()));
1600 break;
1601 case psOpGe:
1602 if (stack->topTwoAreInts()) {
1603 i2 = stack->popInt();
1604 i1 = stack->popInt();
1605 stack->pushBool(i1 >= i2);
1606 } else {
1607 r2 = stack->popNum();
1608 r1 = stack->popNum();
1609 stack->pushBool(r1 >= r2);
1611 break;
1612 case psOpGt:
1613 if (stack->topTwoAreInts()) {
1614 i2 = stack->popInt();
1615 i1 = stack->popInt();
1616 stack->pushBool(i1 > i2);
1617 } else {
1618 r2 = stack->popNum();
1619 r1 = stack->popNum();
1620 stack->pushBool(r1 > r2);
1622 break;
1623 case psOpIdiv:
1624 i2 = stack->popInt();
1625 i1 = stack->popInt();
1626 stack->pushInt(i1 / i2);
1627 break;
1628 case psOpIndex:
1629 stack->index(stack->popInt());
1630 break;
1631 case psOpLe:
1632 if (stack->topTwoAreInts()) {
1633 i2 = stack->popInt();
1634 i1 = stack->popInt();
1635 stack->pushBool(i1 <= i2);
1636 } else {
1637 r2 = stack->popNum();
1638 r1 = stack->popNum();
1639 stack->pushBool(r1 <= r2);
1641 break;
1642 case psOpLn:
1643 stack->pushReal(log(stack->popNum()));
1644 break;
1645 case psOpLog:
1646 stack->pushReal(log10(stack->popNum()));
1647 break;
1648 case psOpLt:
1649 if (stack->topTwoAreInts()) {
1650 i2 = stack->popInt();
1651 i1 = stack->popInt();
1652 stack->pushBool(i1 < i2);
1653 } else {
1654 r2 = stack->popNum();
1655 r1 = stack->popNum();
1656 stack->pushBool(r1 < r2);
1658 break;
1659 case psOpMod:
1660 i2 = stack->popInt();
1661 i1 = stack->popInt();
1662 stack->pushInt(i1 % i2);
1663 break;
1664 case psOpMul:
1665 if (stack->topTwoAreInts()) {
1666 i2 = stack->popInt();
1667 i1 = stack->popInt();
1668 //~ should check for out-of-range, and push a real instead
1669 stack->pushInt(i1 * i2);
1670 } else {
1671 r2 = stack->popNum();
1672 r1 = stack->popNum();
1673 stack->pushReal(r1 * r2);
1675 break;
1676 case psOpNe:
1677 if (stack->topTwoAreInts()) {
1678 i2 = stack->popInt();
1679 i1 = stack->popInt();
1680 stack->pushBool(i1 != i2);
1681 } else if (stack->topTwoAreNums()) {
1682 r2 = stack->popNum();
1683 r1 = stack->popNum();
1684 stack->pushBool(r1 != r2);
1685 } else {
1686 b2 = stack->popBool();
1687 b1 = stack->popBool();
1688 stack->pushBool(b1 != b2);
1690 break;
1691 case psOpNeg:
1692 if (stack->topIsInt()) {
1693 stack->pushInt(-stack->popInt());
1694 } else {
1695 stack->pushReal(-stack->popNum());
1697 break;
1698 case psOpNot:
1699 if (stack->topIsInt()) {
1700 stack->pushInt(~stack->popInt());
1701 } else {
1702 stack->pushBool(!stack->popBool());
1704 break;
1705 case psOpOr:
1706 if (stack->topTwoAreInts()) {
1707 i2 = stack->popInt();
1708 i1 = stack->popInt();
1709 stack->pushInt(i1 | i2);
1710 } else {
1711 b2 = stack->popBool();
1712 b1 = stack->popBool();
1713 stack->pushBool(b1 || b2);
1715 break;
1716 case psOpPop:
1717 stack->pop();
1718 break;
1719 case psOpRoll:
1720 i2 = stack->popInt();
1721 i1 = stack->popInt();
1722 stack->roll(i1, i2);
1723 break;
1724 case psOpRound:
1725 if (!stack->topIsInt()) {
1726 r1 = stack->popNum();
1727 stack->pushReal((r1 >= 0) ? floor(r1 + 0.5) : ceil(r1 - 0.5));
1729 break;
1730 case psOpSin:
1731 stack->pushReal(sin(stack->popNum() * M_PI / 180.0));
1732 break;
1733 case psOpSqrt:
1734 stack->pushReal(sqrt(stack->popNum()));
1735 break;
1736 case psOpSub:
1737 if (stack->topTwoAreInts()) {
1738 i2 = stack->popInt();
1739 i1 = stack->popInt();
1740 stack->pushInt(i1 - i2);
1741 } else {
1742 r2 = stack->popNum();
1743 r1 = stack->popNum();
1744 stack->pushReal(r1 - r2);
1746 break;
1747 case psOpTrue:
1748 stack->pushBool(gTrue);
1749 break;
1750 case psOpTruncate:
1751 if (!stack->topIsInt()) {
1752 r1 = stack->popNum();
1753 stack->pushReal((r1 >= 0) ? floor(r1) : ceil(r1));
1755 break;
1756 case psOpXor:
1757 if (stack->topTwoAreInts()) {
1758 i2 = stack->popInt();
1759 i1 = stack->popInt();
1760 stack->pushInt(i1 ^ i2);
1761 } else {
1762 b2 = stack->popBool();
1763 b1 = stack->popBool();
1764 stack->pushBool(b1 ^ b2);
1766 break;
1767 case psOpIf:
1768 b1 = stack->popBool();
1769 if (b1) {
1770 exec(stack, codePtr + 2);
1772 codePtr = code[codePtr + 1].blk;
1773 break;
1774 case psOpIfelse:
1775 b1 = stack->popBool();
1776 if (b1) {
1777 exec(stack, codePtr + 2);
1778 } else {
1779 exec(stack, code[codePtr].blk);
1781 codePtr = code[codePtr + 1].blk;
1782 break;
1783 case psOpReturn:
1784 return;
1786 break;
1787 default:
1788 error(errSyntaxError, -1, "Internal: bad object in PostScript function code");
1789 break;