a patch for ttc fonts with bad index
[luatex.git] / source / libs / poppler / poppler-0.36.0 / poppler / Function.cc
blob67283dffe9f03619b039d9158a0efd53b049b978
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, 2014 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 for (i = 0; i < n; ++i) {
581 obj1.arrayGet(i, &obj2);
582 if (!obj2.isNum()) {
583 error(errSyntaxError, -1, "Illegal value in function C0 array");
584 goto err3;
586 c0[i] = obj2.getNum();
587 obj2.free();
589 } else {
590 if (hasRange && n != 1) {
591 error(errSyntaxError, -1, "Function's C0 array is wrong length");
592 goto err2;
594 n = 1;
595 c0[0] = 0;
597 obj1.free();
599 //----- C1
600 if (dict->lookup("C1", &obj1)->isArray()) {
601 if (obj1.arrayGetLength() != n) {
602 error(errSyntaxError, -1, "Function's C1 array is wrong length");
603 goto err2;
605 for (i = 0; i < n; ++i) {
606 obj1.arrayGet(i, &obj2);
607 if (!obj2.isNum()) {
608 error(errSyntaxError, -1, "Illegal value in function C1 array");
609 goto err3;
611 c1[i] = obj2.getNum();
612 obj2.free();
614 } else {
615 if (n != 1) {
616 error(errSyntaxError, -1, "Function's C1 array is wrong length");
617 goto err2;
619 c1[0] = 1;
621 obj1.free();
623 //----- N (exponent)
624 if (!dict->lookup("N", &obj1)->isNum()) {
625 error(errSyntaxError, -1, "Function has missing or invalid N");
626 goto err2;
628 e = obj1.getNum();
629 obj1.free();
631 isLinear = fabs(e-1.) < 1e-10;
632 ok = gTrue;
633 return;
635 err3:
636 obj2.free();
637 err2:
638 obj1.free();
639 err1:
640 return;
643 ExponentialFunction::~ExponentialFunction() {
646 ExponentialFunction::ExponentialFunction(const ExponentialFunction *func) : Function(func) {
647 memcpy(c0, func->c0, funcMaxOutputs * sizeof(double));
648 memcpy(c1, func->c1, funcMaxOutputs * sizeof(double));
650 e = func->e;
651 isLinear = func->isLinear;
652 ok = func->ok;
655 void ExponentialFunction::transform(double *in, double *out) {
656 double x;
657 int i;
659 if (in[0] < domain[0][0]) {
660 x = domain[0][0];
661 } else if (in[0] > domain[0][1]) {
662 x = domain[0][1];
663 } else {
664 x = in[0];
666 for (i = 0; i < n; ++i) {
667 out[i] = c0[i] + (isLinear ? x : pow(x, e)) * (c1[i] - c0[i]);
668 if (hasRange) {
669 if (out[i] < range[i][0]) {
670 out[i] = range[i][0];
671 } else if (out[i] > range[i][1]) {
672 out[i] = range[i][1];
676 return;
679 //------------------------------------------------------------------------
680 // StitchingFunction
681 //------------------------------------------------------------------------
683 StitchingFunction::StitchingFunction(Object *funcObj, Dict *dict, std::set<int> *usedParents) {
684 Object obj1, obj2;
685 int i;
687 ok = gFalse;
688 funcs = NULL;
689 bounds = NULL;
690 encode = NULL;
691 scale = NULL;
693 //----- initialize the generic stuff
694 if (!init(dict)) {
695 goto err1;
697 if (m != 1) {
698 error(errSyntaxError, -1, "Stitching function with more than one input");
699 goto err1;
702 //----- Functions
703 if (!dict->lookup("Functions", &obj1)->isArray()) {
704 error(errSyntaxError, -1, "Missing 'Functions' entry in stitching function");
705 goto err1;
707 k = obj1.arrayGetLength();
708 funcs = (Function **)gmallocn(k, sizeof(Function *));
709 bounds = (double *)gmallocn(k + 1, sizeof(double));
710 encode = (double *)gmallocn(2 * k, sizeof(double));
711 scale = (double *)gmallocn(k, sizeof(double));
712 for (i = 0; i < k; ++i) {
713 funcs[i] = NULL;
715 for (i = 0; i < k; ++i) {
716 std::set<int> usedParentsAux = *usedParents;
717 obj1.arrayGetNF(i, &obj2);
718 if (obj2.isRef()) {
719 const Ref ref = obj2.getRef();
720 if (usedParentsAux.find(ref.num) == usedParentsAux.end()) {
721 usedParentsAux.insert(ref.num);
722 obj2.free();
723 obj1.arrayGet(i, &obj2);
724 } else {
725 goto err2;
728 if (!(funcs[i] = Function::parse(&obj2, &usedParentsAux))) {
729 goto err2;
731 if (funcs[i]->getInputSize() != 1 ||
732 (i > 0 && funcs[i]->getOutputSize() != funcs[0]->getOutputSize())) {
733 error(errSyntaxError, -1,
734 "Incompatible subfunctions in stitching function");
735 goto err2;
737 obj2.free();
739 obj1.free();
741 //----- Bounds
742 if (!dict->lookup("Bounds", &obj1)->isArray() ||
743 obj1.arrayGetLength() != k - 1) {
744 error(errSyntaxError, -1, "Missing or invalid 'Bounds' entry in stitching function");
745 goto err1;
747 bounds[0] = domain[0][0];
748 for (i = 1; i < k; ++i) {
749 if (!obj1.arrayGet(i - 1, &obj2)->isNum()) {
750 error(errSyntaxError, -1, "Invalid type in 'Bounds' array in stitching function");
751 goto err2;
753 bounds[i] = obj2.getNum();
754 obj2.free();
756 bounds[k] = domain[0][1];
757 obj1.free();
759 //----- Encode
760 if (!dict->lookup("Encode", &obj1)->isArray() ||
761 obj1.arrayGetLength() != 2 * k) {
762 error(errSyntaxError, -1, "Missing or invalid 'Encode' entry in stitching function");
763 goto err1;
765 for (i = 0; i < 2 * k; ++i) {
766 if (!obj1.arrayGet(i, &obj2)->isNum()) {
767 error(errSyntaxError, -1, "Invalid type in 'Encode' array in stitching function");
768 goto err2;
770 encode[i] = obj2.getNum();
771 obj2.free();
773 obj1.free();
775 //----- pre-compute the scale factors
776 for (i = 0; i < k; ++i) {
777 if (bounds[i] == bounds[i+1]) {
778 // avoid a divide-by-zero -- in this situation, function i will
779 // never be used anyway
780 scale[i] = 0;
781 } else {
782 scale[i] = (encode[2*i+1] - encode[2*i]) / (bounds[i+1] - bounds[i]);
786 n = funcs[0]->getOutputSize();
787 ok = gTrue;
788 return;
790 err2:
791 obj2.free();
792 err1:
793 obj1.free();
796 StitchingFunction::StitchingFunction(const StitchingFunction *func) : Function(func) {
797 k = func->k;
799 funcs = (Function **)gmallocn(k, sizeof(Function *));
800 for (int i = 0; i < k; ++i) {
801 funcs[i] = func->funcs[i]->copy();
804 bounds = (double *)gmallocn(k + 1, sizeof(double));
805 memcpy(bounds, func->bounds, (k + 1) * sizeof(double));
807 encode = (double *)gmallocn(2 * k, sizeof(double));
808 memcpy(encode, func->encode, 2 * k * sizeof(double));
810 scale = (double *)gmallocn(k, sizeof(double));
811 memcpy(scale, func->scale, k * sizeof(double));
813 ok = func->ok;
816 StitchingFunction::~StitchingFunction() {
817 int i;
819 if (funcs) {
820 for (i = 0; i < k; ++i) {
821 if (funcs[i]) {
822 delete funcs[i];
826 gfree(funcs);
827 gfree(bounds);
828 gfree(encode);
829 gfree(scale);
832 void StitchingFunction::transform(double *in, double *out) {
833 double x;
834 int i;
836 if (in[0] < domain[0][0]) {
837 x = domain[0][0];
838 } else if (in[0] > domain[0][1]) {
839 x = domain[0][1];
840 } else {
841 x = in[0];
843 for (i = 0; i < k - 1; ++i) {
844 if (x < bounds[i+1]) {
845 break;
848 x = encode[2*i] + (x - bounds[i]) * scale[i];
849 funcs[i]->transform(&x, out);
852 //------------------------------------------------------------------------
853 // PostScriptFunction
854 //------------------------------------------------------------------------
856 enum PSOp {
857 psOpAbs,
858 psOpAdd,
859 psOpAnd,
860 psOpAtan,
861 psOpBitshift,
862 psOpCeiling,
863 psOpCopy,
864 psOpCos,
865 psOpCvi,
866 psOpCvr,
867 psOpDiv,
868 psOpDup,
869 psOpEq,
870 psOpExch,
871 psOpExp,
872 psOpFalse,
873 psOpFloor,
874 psOpGe,
875 psOpGt,
876 psOpIdiv,
877 psOpIndex,
878 psOpLe,
879 psOpLn,
880 psOpLog,
881 psOpLt,
882 psOpMod,
883 psOpMul,
884 psOpNe,
885 psOpNeg,
886 psOpNot,
887 psOpOr,
888 psOpPop,
889 psOpRoll,
890 psOpRound,
891 psOpSin,
892 psOpSqrt,
893 psOpSub,
894 psOpTrue,
895 psOpTruncate,
896 psOpXor,
897 psOpIf,
898 psOpIfelse,
899 psOpReturn
902 // Note: 'if' and 'ifelse' are parsed separately.
903 // The rest are listed here in alphabetical order.
904 // The index in this table is equivalent to the entry in PSOp.
905 static const char *psOpNames[] = {
906 "abs",
907 "add",
908 "and",
909 "atan",
910 "bitshift",
911 "ceiling",
912 "copy",
913 "cos",
914 "cvi",
915 "cvr",
916 "div",
917 "dup",
918 "eq",
919 "exch",
920 "exp",
921 "false",
922 "floor",
923 "ge",
924 "gt",
925 "idiv",
926 "index",
927 "le",
928 "ln",
929 "log",
930 "lt",
931 "mod",
932 "mul",
933 "ne",
934 "neg",
935 "not",
936 "or",
937 "pop",
938 "roll",
939 "round",
940 "sin",
941 "sqrt",
942 "sub",
943 "true",
944 "truncate",
945 "xor"
948 #define nPSOps (sizeof(psOpNames) / sizeof(char *))
950 enum PSObjectType {
951 psBool,
952 psInt,
953 psReal,
954 psOperator,
955 psBlock
958 // In the code array, 'if'/'ifelse' operators take up three slots
959 // plus space for the code in the subclause(s).
961 // +---------------------------------+
962 // | psOperator: psOpIf / psOpIfelse |
963 // +---------------------------------+
964 // | psBlock: ptr=<A> |
965 // +---------------------------------+
966 // | psBlock: ptr=<B> |
967 // +---------------------------------+
968 // | if clause |
969 // | ... |
970 // | psOperator: psOpReturn |
971 // +---------------------------------+
972 // <A> | else clause |
973 // | ... |
974 // | psOperator: psOpReturn |
975 // +---------------------------------+
976 // <B> | ... |
978 // For 'if', pointer <A> is present in the code stream but unused.
980 struct PSObject {
981 PSObjectType type;
982 union {
983 GBool booln; // boolean (stack only)
984 int intg; // integer (stack and code)
985 double real; // real (stack and code)
986 PSOp op; // operator (code only)
987 int blk; // if/ifelse block pointer (code only)
991 #define psStackSize 100
993 class PSStack {
994 public:
996 PSStack() {sp = psStackSize; }
997 void clear() { sp = psStackSize; }
998 void pushBool(GBool booln)
1000 if (checkOverflow()) {
1001 stack[--sp].type = psBool;
1002 stack[sp].booln = booln;
1005 void pushInt(int intg)
1007 if (checkOverflow()) {
1008 stack[--sp].type = psInt;
1009 stack[sp].intg = intg;
1012 void pushReal(double real)
1014 if (checkOverflow()) {
1015 stack[--sp].type = psReal;
1016 stack[sp].real = real;
1019 GBool popBool()
1021 if (checkUnderflow() && checkType(psBool, psBool)) {
1022 return stack[sp++].booln;
1024 return gFalse;
1026 int popInt()
1028 if (checkUnderflow() && checkType(psInt, psInt)) {
1029 return stack[sp++].intg;
1031 return 0;
1033 double popNum()
1035 double ret;
1037 if (checkUnderflow() && checkType(psInt, psReal)) {
1038 ret = (stack[sp].type == psInt) ? (double)stack[sp].intg : stack[sp].real;
1039 ++sp;
1040 return ret;
1042 return 0;
1044 GBool empty() { return sp == psStackSize; }
1045 GBool topIsInt() { return sp < psStackSize && stack[sp].type == psInt; }
1046 GBool topTwoAreInts()
1047 { return sp < psStackSize - 1 &&
1048 stack[sp].type == psInt &&
1049 stack[sp+1].type == psInt; }
1050 GBool topIsReal() { return sp < psStackSize && stack[sp].type == psReal; }
1051 GBool topTwoAreNums()
1052 { return sp < psStackSize - 1 &&
1053 (stack[sp].type == psInt || stack[sp].type == psReal) &&
1054 (stack[sp+1].type == psInt || stack[sp+1].type == psReal); }
1055 void copy(int n);
1056 void roll(int n, int j);
1057 void index(int i)
1059 if (!checkOverflow()) {
1060 return;
1062 --sp;
1063 if (unlikely(sp + i + 1 >= psStackSize)) {
1064 error(errSyntaxError, -1, "Stack underflow in PostScript function");
1065 return;
1067 if (unlikely(sp + i + 1 < 0)) {
1068 error(errSyntaxError, -1, "Stack overflow in PostScript function");
1069 return;
1071 stack[sp] = stack[sp + 1 + i];
1073 void pop()
1075 if (!checkUnderflow()) {
1076 return;
1078 ++sp;
1081 private:
1083 GBool checkOverflow(int n = 1)
1085 if (sp - n < 0) {
1086 error(errSyntaxError, -1, "Stack overflow in PostScript function");
1087 return gFalse;
1089 return gTrue;
1091 GBool checkUnderflow()
1093 if (sp == psStackSize) {
1094 error(errSyntaxError, -1, "Stack underflow in PostScript function");
1095 return gFalse;
1097 return gTrue;
1099 GBool checkType(PSObjectType t1, PSObjectType t2)
1101 if (stack[sp].type != t1 && stack[sp].type != t2) {
1102 error(errSyntaxError, -1, "Type mismatch in PostScript function");
1103 return gFalse;
1105 return gTrue;
1107 PSObject stack[psStackSize];
1108 int sp;
1112 void PSStack::copy(int n) {
1113 int i;
1115 if (sp + n > psStackSize) {
1116 error(errSyntaxError, -1, "Stack underflow in PostScript function");
1117 return;
1119 if (unlikely(sp - n > psStackSize)) {
1120 error(errSyntaxError, -1, "Stack underflow in PostScript function");
1121 return;
1123 if (!checkOverflow(n)) {
1124 return;
1126 for (i = sp + n - 1; i >= sp; --i) {
1127 stack[i - n] = stack[i];
1129 sp -= n;
1132 void PSStack::roll(int n, int j) {
1133 PSObject obj;
1134 int i, k;
1136 if (unlikely(n == 0)) {
1137 return;
1139 if (j >= 0) {
1140 j %= n;
1141 } else {
1142 j = -j % n;
1143 if (j != 0) {
1144 j = n - j;
1147 if (n <= 0 || j == 0 || n > psStackSize || sp + n > psStackSize) {
1148 return;
1150 if (j <= n / 2) {
1151 for (i = 0; i < j; ++i) {
1152 obj = stack[sp];
1153 for (k = sp; k < sp + n - 1; ++k) {
1154 stack[k] = stack[k+1];
1156 stack[sp + n - 1] = obj;
1158 } else {
1159 j = n - j;
1160 for (i = 0; i < j; ++i) {
1161 obj = stack[sp + n - 1];
1162 for (k = sp + n - 1; k > sp; --k) {
1163 stack[k] = stack[k-1];
1165 stack[sp] = obj;
1170 PostScriptFunction::PostScriptFunction(Object *funcObj, Dict *dict) {
1171 Stream *str;
1172 int codePtr;
1173 GooString *tok;
1174 double in[funcMaxInputs];
1175 int i;
1177 code = NULL;
1178 codeString = NULL;
1179 codeSize = 0;
1180 ok = gFalse;
1182 //----- initialize the generic stuff
1183 if (!init(dict)) {
1184 goto err1;
1186 if (!hasRange) {
1187 error(errSyntaxError, -1, "Type 4 function is missing range");
1188 goto err1;
1191 //----- get the stream
1192 if (!funcObj->isStream()) {
1193 error(errSyntaxError, -1, "Type 4 function isn't a stream");
1194 goto err1;
1196 str = funcObj->getStream();
1198 //----- parse the function
1199 codeString = new GooString();
1200 str->reset();
1201 if (!(tok = getToken(str)) || tok->cmp("{")) {
1202 error(errSyntaxError, -1, "Expected '{{' at start of PostScript function");
1203 if (tok) {
1204 delete tok;
1206 goto err1;
1208 delete tok;
1209 codePtr = 0;
1210 if (!parseCode(str, &codePtr)) {
1211 goto err2;
1213 str->close();
1215 //----- set up the cache
1216 for (i = 0; i < m; ++i) {
1217 in[i] = domain[i][0];
1218 cacheIn[i] = in[i] - 1;
1220 transform(in, cacheOut);
1222 ok = gTrue;
1224 err2:
1225 str->close();
1226 err1:
1227 return;
1230 PostScriptFunction::PostScriptFunction(const PostScriptFunction *func) : Function(func) {
1231 codeSize = func->codeSize;
1233 code = (PSObject *)gmallocn(codeSize, sizeof(PSObject));
1234 memcpy(code, func->code, codeSize * sizeof(PSObject));
1236 codeString = func->codeString->copy();
1238 memcpy(cacheIn, func->cacheIn, funcMaxInputs * sizeof(double));
1239 memcpy(cacheOut, func->cacheOut, funcMaxOutputs * sizeof(double));
1241 ok = func->ok;
1244 PostScriptFunction::~PostScriptFunction() {
1245 gfree(code);
1246 delete codeString;
1249 void PostScriptFunction::transform(double *in, double *out) {
1250 PSStack stack;
1251 int i;
1253 // check the cache
1254 for (i = 0; i < m; ++i) {
1255 if (in[i] != cacheIn[i]) {
1256 break;
1259 if (i == m) {
1260 for (i = 0; i < n; ++i) {
1261 out[i] = cacheOut[i];
1263 return;
1266 for (i = 0; i < m; ++i) {
1267 //~ may need to check for integers here
1268 stack.pushReal(in[i]);
1270 exec(&stack, 0);
1271 for (i = n - 1; i >= 0; --i) {
1272 out[i] = stack.popNum();
1273 if (out[i] < range[i][0]) {
1274 out[i] = range[i][0];
1275 } else if (out[i] > range[i][1]) {
1276 out[i] = range[i][1];
1279 stack.clear();
1281 // if (!stack->empty()) {
1282 // error(errSyntaxWarning, -1,
1283 // "Extra values on stack at end of PostScript function");
1284 // }
1286 // save current result in the cache
1287 for (i = 0; i < m; ++i) {
1288 cacheIn[i] = in[i];
1290 for (i = 0; i < n; ++i) {
1291 cacheOut[i] = out[i];
1295 GBool PostScriptFunction::parseCode(Stream *str, int *codePtr) {
1296 GooString *tok;
1297 char *p;
1298 GBool isReal;
1299 int opPtr, elsePtr;
1300 int a, b, mid, cmp;
1302 while (1) {
1303 if (!(tok = getToken(str))) {
1304 error(errSyntaxError, -1, "Unexpected end of PostScript function stream");
1305 return gFalse;
1307 p = tok->getCString();
1308 if (isdigit(*p) || *p == '.' || *p == '-') {
1309 isReal = gFalse;
1310 for (; *p; ++p) {
1311 if (*p == '.') {
1312 isReal = gTrue;
1313 break;
1316 resizeCode(*codePtr);
1317 if (isReal) {
1318 code[*codePtr].type = psReal;
1319 code[*codePtr].real = gatof(tok->getCString());
1320 } else {
1321 code[*codePtr].type = psInt;
1322 code[*codePtr].intg = atoi(tok->getCString());
1324 ++*codePtr;
1325 delete tok;
1326 } else if (!tok->cmp("{")) {
1327 delete tok;
1328 opPtr = *codePtr;
1329 *codePtr += 3;
1330 resizeCode(opPtr + 2);
1331 if (!parseCode(str, codePtr)) {
1332 return gFalse;
1334 if (!(tok = getToken(str))) {
1335 error(errSyntaxError, -1, "Unexpected end of PostScript function stream");
1336 return gFalse;
1338 if (!tok->cmp("{")) {
1339 elsePtr = *codePtr;
1340 if (!parseCode(str, codePtr)) {
1341 return gFalse;
1343 delete tok;
1344 if (!(tok = getToken(str))) {
1345 error(errSyntaxError, -1, "Unexpected end of PostScript function stream");
1346 return gFalse;
1348 } else {
1349 elsePtr = -1;
1351 if (!tok->cmp("if")) {
1352 if (elsePtr >= 0) {
1353 error(errSyntaxError, -1,
1354 "Got 'if' operator with two blocks in PostScript function");
1355 return gFalse;
1357 code[opPtr].type = psOperator;
1358 code[opPtr].op = psOpIf;
1359 code[opPtr+2].type = psBlock;
1360 code[opPtr+2].blk = *codePtr;
1361 } else if (!tok->cmp("ifelse")) {
1362 if (elsePtr < 0) {
1363 error(errSyntaxError, -1,
1364 "Got 'ifelse' operator with one block in PostScript function");
1365 return gFalse;
1367 code[opPtr].type = psOperator;
1368 code[opPtr].op = psOpIfelse;
1369 code[opPtr+1].type = psBlock;
1370 code[opPtr+1].blk = elsePtr;
1371 code[opPtr+2].type = psBlock;
1372 code[opPtr+2].blk = *codePtr;
1373 } else {
1374 error(errSyntaxError, -1,
1375 "Expected if/ifelse operator in PostScript function");
1376 delete tok;
1377 return gFalse;
1379 delete tok;
1380 } else if (!tok->cmp("}")) {
1381 delete tok;
1382 resizeCode(*codePtr);
1383 code[*codePtr].type = psOperator;
1384 code[*codePtr].op = psOpReturn;
1385 ++*codePtr;
1386 break;
1387 } else {
1388 a = -1;
1389 b = nPSOps;
1390 cmp = 0; // make gcc happy
1391 // invariant: psOpNames[a] < tok < psOpNames[b]
1392 while (b - a > 1) {
1393 mid = (a + b) / 2;
1394 cmp = tok->cmp(psOpNames[mid]);
1395 if (cmp > 0) {
1396 a = mid;
1397 } else if (cmp < 0) {
1398 b = mid;
1399 } else {
1400 a = b = mid;
1403 if (cmp != 0) {
1404 error(errSyntaxError, -1,
1405 "Unknown operator '{0:t}' in PostScript function",
1406 tok);
1407 delete tok;
1408 return gFalse;
1410 delete tok;
1411 resizeCode(*codePtr);
1412 code[*codePtr].type = psOperator;
1413 code[*codePtr].op = (PSOp)a;
1414 ++*codePtr;
1417 return gTrue;
1420 GooString *PostScriptFunction::getToken(Stream *str) {
1421 GooString *s;
1422 int c;
1423 GBool comment;
1425 s = new GooString();
1426 comment = gFalse;
1427 while (1) {
1428 if ((c = str->getChar()) == EOF) {
1429 break;
1431 codeString->append(c);
1432 if (comment) {
1433 if (c == '\x0a' || c == '\x0d') {
1434 comment = gFalse;
1436 } else if (c == '%') {
1437 comment = gTrue;
1438 } else if (!isspace(c)) {
1439 break;
1442 if (c == '{' || c == '}') {
1443 s->append((char)c);
1444 } else if (isdigit(c) || c == '.' || c == '-') {
1445 while (1) {
1446 s->append((char)c);
1447 c = str->lookChar();
1448 if (c == EOF || !(isdigit(c) || c == '.' || c == '-')) {
1449 break;
1451 str->getChar();
1452 codeString->append(c);
1454 } else {
1455 while (1) {
1456 s->append((char)c);
1457 c = str->lookChar();
1458 if (c == EOF || !isalnum(c)) {
1459 break;
1461 str->getChar();
1462 codeString->append(c);
1465 return s;
1468 void PostScriptFunction::resizeCode(int newSize) {
1469 if (newSize >= codeSize) {
1470 codeSize += 64;
1471 code = (PSObject *)greallocn(code, codeSize, sizeof(PSObject));
1475 void PostScriptFunction::exec(PSStack *stack, int codePtr) {
1476 int i1, i2;
1477 double r1, r2, result;
1478 GBool b1, b2;
1480 while (1) {
1481 switch (code[codePtr].type) {
1482 case psInt:
1483 stack->pushInt(code[codePtr++].intg);
1484 break;
1485 case psReal:
1486 stack->pushReal(code[codePtr++].real);
1487 break;
1488 case psOperator:
1489 switch (code[codePtr++].op) {
1490 case psOpAbs:
1491 if (stack->topIsInt()) {
1492 stack->pushInt(abs(stack->popInt()));
1493 } else {
1494 stack->pushReal(fabs(stack->popNum()));
1496 break;
1497 case psOpAdd:
1498 if (stack->topTwoAreInts()) {
1499 i2 = stack->popInt();
1500 i1 = stack->popInt();
1501 stack->pushInt(i1 + i2);
1502 } else {
1503 r2 = stack->popNum();
1504 r1 = stack->popNum();
1505 stack->pushReal(r1 + r2);
1507 break;
1508 case psOpAnd:
1509 if (stack->topTwoAreInts()) {
1510 i2 = stack->popInt();
1511 i1 = stack->popInt();
1512 stack->pushInt(i1 & i2);
1513 } else {
1514 b2 = stack->popBool();
1515 b1 = stack->popBool();
1516 stack->pushBool(b1 && b2);
1518 break;
1519 case psOpAtan:
1520 r2 = stack->popNum();
1521 r1 = stack->popNum();
1522 result = atan2(r1, r2) * 180.0 / M_PI;
1523 if (result < 0) result += 360.0;
1524 stack->pushReal(result);
1525 break;
1526 case psOpBitshift:
1527 i2 = stack->popInt();
1528 i1 = stack->popInt();
1529 if (i2 > 0) {
1530 stack->pushInt(i1 << i2);
1531 } else if (i2 < 0) {
1532 stack->pushInt((int)((Guint)i1 >> -i2));
1533 } else {
1534 stack->pushInt(i1);
1536 break;
1537 case psOpCeiling:
1538 if (!stack->topIsInt()) {
1539 stack->pushReal(ceil(stack->popNum()));
1541 break;
1542 case psOpCopy:
1543 stack->copy(stack->popInt());
1544 break;
1545 case psOpCos:
1546 stack->pushReal(cos(stack->popNum() * M_PI / 180.0));
1547 break;
1548 case psOpCvi:
1549 if (!stack->topIsInt()) {
1550 stack->pushInt((int)stack->popNum());
1552 break;
1553 case psOpCvr:
1554 if (!stack->topIsReal()) {
1555 stack->pushReal(stack->popNum());
1557 break;
1558 case psOpDiv:
1559 r2 = stack->popNum();
1560 r1 = stack->popNum();
1561 stack->pushReal(r1 / r2);
1562 break;
1563 case psOpDup:
1564 stack->copy(1);
1565 break;
1566 case psOpEq:
1567 if (stack->topTwoAreInts()) {
1568 i2 = stack->popInt();
1569 i1 = stack->popInt();
1570 stack->pushBool(i1 == i2);
1571 } else if (stack->topTwoAreNums()) {
1572 r2 = stack->popNum();
1573 r1 = stack->popNum();
1574 stack->pushBool(r1 == r2);
1575 } else {
1576 b2 = stack->popBool();
1577 b1 = stack->popBool();
1578 stack->pushBool(b1 == b2);
1580 break;
1581 case psOpExch:
1582 stack->roll(2, 1);
1583 break;
1584 case psOpExp:
1585 r2 = stack->popNum();
1586 r1 = stack->popNum();
1587 stack->pushReal(pow(r1, r2));
1588 break;
1589 case psOpFalse:
1590 stack->pushBool(gFalse);
1591 break;
1592 case psOpFloor:
1593 if (!stack->topIsInt()) {
1594 stack->pushReal(floor(stack->popNum()));
1596 break;
1597 case psOpGe:
1598 if (stack->topTwoAreInts()) {
1599 i2 = stack->popInt();
1600 i1 = stack->popInt();
1601 stack->pushBool(i1 >= i2);
1602 } else {
1603 r2 = stack->popNum();
1604 r1 = stack->popNum();
1605 stack->pushBool(r1 >= r2);
1607 break;
1608 case psOpGt:
1609 if (stack->topTwoAreInts()) {
1610 i2 = stack->popInt();
1611 i1 = stack->popInt();
1612 stack->pushBool(i1 > i2);
1613 } else {
1614 r2 = stack->popNum();
1615 r1 = stack->popNum();
1616 stack->pushBool(r1 > r2);
1618 break;
1619 case psOpIdiv:
1620 i2 = stack->popInt();
1621 i1 = stack->popInt();
1622 stack->pushInt(i1 / i2);
1623 break;
1624 case psOpIndex:
1625 stack->index(stack->popInt());
1626 break;
1627 case psOpLe:
1628 if (stack->topTwoAreInts()) {
1629 i2 = stack->popInt();
1630 i1 = stack->popInt();
1631 stack->pushBool(i1 <= i2);
1632 } else {
1633 r2 = stack->popNum();
1634 r1 = stack->popNum();
1635 stack->pushBool(r1 <= r2);
1637 break;
1638 case psOpLn:
1639 stack->pushReal(log(stack->popNum()));
1640 break;
1641 case psOpLog:
1642 stack->pushReal(log10(stack->popNum()));
1643 break;
1644 case psOpLt:
1645 if (stack->topTwoAreInts()) {
1646 i2 = stack->popInt();
1647 i1 = stack->popInt();
1648 stack->pushBool(i1 < i2);
1649 } else {
1650 r2 = stack->popNum();
1651 r1 = stack->popNum();
1652 stack->pushBool(r1 < r2);
1654 break;
1655 case psOpMod:
1656 i2 = stack->popInt();
1657 i1 = stack->popInt();
1658 stack->pushInt(i1 % i2);
1659 break;
1660 case psOpMul:
1661 if (stack->topTwoAreInts()) {
1662 i2 = stack->popInt();
1663 i1 = stack->popInt();
1664 //~ should check for out-of-range, and push a real instead
1665 stack->pushInt(i1 * i2);
1666 } else {
1667 r2 = stack->popNum();
1668 r1 = stack->popNum();
1669 stack->pushReal(r1 * r2);
1671 break;
1672 case psOpNe:
1673 if (stack->topTwoAreInts()) {
1674 i2 = stack->popInt();
1675 i1 = stack->popInt();
1676 stack->pushBool(i1 != i2);
1677 } else if (stack->topTwoAreNums()) {
1678 r2 = stack->popNum();
1679 r1 = stack->popNum();
1680 stack->pushBool(r1 != r2);
1681 } else {
1682 b2 = stack->popBool();
1683 b1 = stack->popBool();
1684 stack->pushBool(b1 != b2);
1686 break;
1687 case psOpNeg:
1688 if (stack->topIsInt()) {
1689 stack->pushInt(-stack->popInt());
1690 } else {
1691 stack->pushReal(-stack->popNum());
1693 break;
1694 case psOpNot:
1695 if (stack->topIsInt()) {
1696 stack->pushInt(~stack->popInt());
1697 } else {
1698 stack->pushBool(!stack->popBool());
1700 break;
1701 case psOpOr:
1702 if (stack->topTwoAreInts()) {
1703 i2 = stack->popInt();
1704 i1 = stack->popInt();
1705 stack->pushInt(i1 | i2);
1706 } else {
1707 b2 = stack->popBool();
1708 b1 = stack->popBool();
1709 stack->pushBool(b1 || b2);
1711 break;
1712 case psOpPop:
1713 stack->pop();
1714 break;
1715 case psOpRoll:
1716 i2 = stack->popInt();
1717 i1 = stack->popInt();
1718 stack->roll(i1, i2);
1719 break;
1720 case psOpRound:
1721 if (!stack->topIsInt()) {
1722 r1 = stack->popNum();
1723 stack->pushReal((r1 >= 0) ? floor(r1 + 0.5) : ceil(r1 - 0.5));
1725 break;
1726 case psOpSin:
1727 stack->pushReal(sin(stack->popNum() * M_PI / 180.0));
1728 break;
1729 case psOpSqrt:
1730 stack->pushReal(sqrt(stack->popNum()));
1731 break;
1732 case psOpSub:
1733 if (stack->topTwoAreInts()) {
1734 i2 = stack->popInt();
1735 i1 = stack->popInt();
1736 stack->pushInt(i1 - i2);
1737 } else {
1738 r2 = stack->popNum();
1739 r1 = stack->popNum();
1740 stack->pushReal(r1 - r2);
1742 break;
1743 case psOpTrue:
1744 stack->pushBool(gTrue);
1745 break;
1746 case psOpTruncate:
1747 if (!stack->topIsInt()) {
1748 r1 = stack->popNum();
1749 stack->pushReal((r1 >= 0) ? floor(r1) : ceil(r1));
1751 break;
1752 case psOpXor:
1753 if (stack->topTwoAreInts()) {
1754 i2 = stack->popInt();
1755 i1 = stack->popInt();
1756 stack->pushInt(i1 ^ i2);
1757 } else {
1758 b2 = stack->popBool();
1759 b1 = stack->popBool();
1760 stack->pushBool(b1 ^ b2);
1762 break;
1763 case psOpIf:
1764 b1 = stack->popBool();
1765 if (b1) {
1766 exec(stack, codePtr + 2);
1768 codePtr = code[codePtr + 1].blk;
1769 break;
1770 case psOpIfelse:
1771 b1 = stack->popBool();
1772 if (b1) {
1773 exec(stack, codePtr + 2);
1774 } else {
1775 exec(stack, code[codePtr].blk);
1777 codePtr = code[codePtr + 1].blk;
1778 break;
1779 case psOpReturn:
1780 return;
1782 break;
1783 default:
1784 error(errSyntaxError, -1, "Internal: bad object in PostScript function code");
1785 break;