1 //========================================================================
5 // Copyright 2001-2002 Glyph & Cog, LLC
7 //========================================================================
11 #ifdef USE_GCC_PRAGMAS
12 #pragma implementation
27 //------------------------------------------------------------------------
29 //------------------------------------------------------------------------
31 Function::Function() {
34 Function::~Function() {
37 Function *Function::parse(Object *funcObj) {
43 if (funcObj->isStream()) {
44 dict = funcObj->streamGetDict();
45 } else if (funcObj->isDict()) {
46 dict = funcObj->getDict();
47 } else if (funcObj->isName("Identity")) {
48 return new IdentityFunction();
50 error(-1, "Expected function dictionary or stream");
54 if (!dict->lookup("FunctionType", &obj1)->isInt()) {
55 error(-1, "Function type is missing or wrong type");
59 funcType = obj1.getInt();
63 func = new SampledFunction(funcObj, dict);
64 } else if (funcType == 2) {
65 func = new ExponentialFunction(funcObj, dict);
66 } else if (funcType == 3) {
67 func = new StitchingFunction(funcObj, dict);
68 } else if (funcType == 4) {
69 func = new PostScriptFunction(funcObj, dict);
71 error(-1, "Unimplemented function type (%d)", funcType);
82 GBool Function::init(Dict *dict) {
87 if (!dict->lookup("Domain", &obj1)->isArray()) {
88 error(-1, "Function is missing domain");
91 m = obj1.arrayGetLength() / 2;
92 if (m > funcMaxInputs) {
93 error(-1, "Functions with more than %d inputs are unsupported",
97 for (i = 0; i < m; ++i) {
98 obj1.arrayGet(2*i, &obj2);
100 error(-1, "Illegal value in function domain array");
103 domain[i][0] = obj2.getNum();
105 obj1.arrayGet(2*i+1, &obj2);
107 error(-1, "Illegal value in function domain array");
110 domain[i][1] = obj2.getNum();
118 if (dict->lookup("Range", &obj1)->isArray()) {
120 n = obj1.arrayGetLength() / 2;
121 if (n > funcMaxOutputs) {
122 error(-1, "Functions with more than %d outputs are unsupported",
126 for (i = 0; i < n; ++i) {
127 obj1.arrayGet(2*i, &obj2);
129 error(-1, "Illegal value in function range array");
132 range[i][0] = obj2.getNum();
134 obj1.arrayGet(2*i+1, &obj2);
136 error(-1, "Illegal value in function range array");
139 range[i][1] = obj2.getNum();
154 //------------------------------------------------------------------------
156 //------------------------------------------------------------------------
158 IdentityFunction::IdentityFunction() {
161 // fill these in with arbitrary values just in case they get used
165 for (i = 0; i < funcMaxInputs; ++i) {
172 IdentityFunction::~IdentityFunction() {
175 void IdentityFunction::transform(double *in, double *out) {
178 for (i = 0; i < funcMaxOutputs; ++i) {
183 //------------------------------------------------------------------------
185 //------------------------------------------------------------------------
187 SampledFunction::SampledFunction(Object *funcObj, Dict *dict) {
189 int nSamples, sampleBits;
200 //----- initialize the generic stuff
205 error(-1, "Type 0 function is missing range");
209 //----- get the stream
210 if (!funcObj->isStream()) {
211 error(-1, "Type 0 function isn't a stream");
214 str = funcObj->getStream();
217 if (!dict->lookup("Size", &obj1)->isArray() ||
218 obj1.arrayGetLength() != m) {
219 error(-1, "Function has missing or invalid size array");
222 for (i = 0; i < m; ++i) {
223 obj1.arrayGet(i, &obj2);
225 error(-1, "Illegal value in function size array");
228 sampleSize[i] = obj2.getInt();
233 //----- BitsPerSample
234 if (!dict->lookup("BitsPerSample", &obj1)->isInt()) {
235 error(-1, "Function has missing or invalid BitsPerSample");
238 sampleBits = obj1.getInt();
239 sampleMul = 1.0 / (double)((1 << sampleBits) - 1);
243 if (dict->lookup("Encode", &obj1)->isArray() &&
244 obj1.arrayGetLength() == 2*m) {
245 for (i = 0; i < m; ++i) {
246 obj1.arrayGet(2*i, &obj2);
248 error(-1, "Illegal value in function encode array");
251 encode[i][0] = obj2.getNum();
253 obj1.arrayGet(2*i+1, &obj2);
255 error(-1, "Illegal value in function encode array");
258 encode[i][1] = obj2.getNum();
262 for (i = 0; i < m; ++i) {
264 encode[i][1] = sampleSize[i] - 1;
270 if (dict->lookup("Decode", &obj1)->isArray() &&
271 obj1.arrayGetLength() == 2*n) {
272 for (i = 0; i < n; ++i) {
273 obj1.arrayGet(2*i, &obj2);
275 error(-1, "Illegal value in function decode array");
278 decode[i][0] = obj2.getNum();
280 obj1.arrayGet(2*i+1, &obj2);
282 error(-1, "Illegal value in function decode array");
285 decode[i][1] = obj2.getNum();
289 for (i = 0; i < n; ++i) {
290 decode[i][0] = range[i][0];
291 decode[i][1] = range[i][1];
298 for (i = 0; i < m; ++i)
299 nSamples *= sampleSize[i];
300 samples = (double *)gmalloc(nSamples * sizeof(double));
303 bitMask = (1 << sampleBits) - 1;
305 for (i = 0; i < nSamples; ++i) {
306 if (sampleBits == 8) {
308 } else if (sampleBits == 16) {
310 s = (s << 8) + str->getChar();
311 } else if (sampleBits == 32) {
313 s = (s << 8) + str->getChar();
314 s = (s << 8) + str->getChar();
315 s = (s << 8) + str->getChar();
317 while (bits < sampleBits) {
318 buf = (buf << 8) | (str->getChar() & 0xff);
321 s = (buf >> (bits - sampleBits)) & bitMask;
324 samples[i] = (double)s * sampleMul;
339 SampledFunction::~SampledFunction() {
345 SampledFunction::SampledFunction(SampledFunction *func) {
348 memcpy(this, func, sizeof(SampledFunction));
351 for (i = 0; i < m; ++i) {
352 nSamples *= sampleSize[i];
354 samples = (double *)gmalloc(nSamples * sizeof(double));
355 memcpy(samples, func->samples, nSamples * sizeof(double));
358 void SampledFunction::transform(double *in, double *out) {
360 int e[2][funcMaxInputs];
361 double efrac[funcMaxInputs];
362 double s0[1 << funcMaxInputs], s1[1 << funcMaxInputs];
365 // map input values into sample array
366 for (i = 0; i < m; ++i) {
367 x = ((in[i] - domain[i][0]) / (domain[i][1] - domain[i][0])) *
368 (encode[i][1] - encode[i][0]) + encode[i][0];
371 } else if (x > sampleSize[i] - 1) {
372 x = sampleSize[i] - 1;
374 e[0][i] = (int)floor(x);
375 e[1][i] = (int)ceil(x);
376 efrac[i] = x - e[0][i];
379 // for each output, do m-linear interpolation
380 for (i = 0; i < n; ++i) {
382 // pull 2^m values out of the sample array
383 for (j = 0; j < (1<<m); ++j) {
384 idx = e[j & 1][m - 1];
385 for (k = m - 2; k >= 0; --k) {
386 idx = idx * sampleSize[k] + e[(j >> k) & 1][k];
389 s0[j] = samples[idx];
392 // do m sets of interpolations
393 for (j = 0; j < m; ++j) {
394 for (k = 0; k < (1 << (m - j)); k += 2) {
395 s1[k >> 1] = (1 - efrac[j]) * s0[k] + efrac[j] * s0[k+1];
397 memcpy(s0, s1, (1 << (m - j - 1)) * sizeof(double));
400 // map output value to range
401 out[i] = s0[0] * (decode[i][1] - decode[i][0]) + decode[i][0];
402 if (out[i] < range[i][0]) {
403 out[i] = range[i][0];
404 } else if (out[i] > range[i][1]) {
405 out[i] = range[i][1];
410 //------------------------------------------------------------------------
411 // ExponentialFunction
412 //------------------------------------------------------------------------
414 ExponentialFunction::ExponentialFunction(Object *funcObj, Dict *dict) {
421 //----- initialize the generic stuff
426 error(-1, "Exponential function with more than one input");
431 //----- default values
432 for (i = 0; i < funcMaxOutputs; ++i) {
438 if (dict->lookup("C0", &obj1)->isArray()) {
440 n = obj1.arrayGetLength();
442 } else if (obj1.arrayGetLength() != n) {
443 error(-1, "Function's C0 array is wrong length");
446 for (i = 0; i < n; ++i) {
447 obj1.arrayGet(i, &obj2);
449 error(-1, "Illegal value in function C0 array");
452 c0[i] = obj2.getNum();
459 if (dict->lookup("C1", &obj1)->isArray()) {
461 n = obj1.arrayGetLength();
463 } else if (obj1.arrayGetLength() != n) {
464 error(-1, "Function's C1 array is wrong length");
467 for (i = 0; i < n; ++i) {
468 obj1.arrayGet(i, &obj2);
470 error(-1, "Illegal value in function C1 array");
473 c1[i] = obj2.getNum();
480 if (!dict->lookup("N", &obj1)->isNum()) {
481 error(-1, "Function has missing or invalid N");
487 // this isn't supposed to happen, but I've run into (broken) PDF
488 // files where it does
490 error(-1, "Exponential function does not define number of output values");
505 ExponentialFunction::~ExponentialFunction() {
508 ExponentialFunction::ExponentialFunction(ExponentialFunction *func) {
509 memcpy(this, func, sizeof(ExponentialFunction));
512 void ExponentialFunction::transform(double *in, double *out) {
516 if (in[0] < domain[0][0]) {
518 } else if (in[0] > domain[0][1]) {
523 for (i = 0; i < n; ++i) {
524 out[i] = c0[i] + pow(x, e) * (c1[i] - c0[i]);
526 if (out[i] < range[i][0]) {
527 out[i] = range[i][0];
528 } else if (out[i] > range[i][1]) {
529 out[i] = range[i][1];
536 //------------------------------------------------------------------------
538 //------------------------------------------------------------------------
540 StitchingFunction::StitchingFunction(Object *funcObj, Dict *dict) {
549 //----- initialize the generic stuff
554 error(-1, "Stitching function with more than one input");
559 if (!dict->lookup("Functions", &obj1)->isArray()) {
560 error(-1, "Missing 'Functions' entry in stitching function");
563 k = obj1.arrayGetLength();
564 funcs = (Function **)gmalloc(k * sizeof(Function *));
565 bounds = (double *)gmalloc((k + 1) * sizeof(double));
566 encode = (double *)gmalloc(2 * k * sizeof(double));
567 for (i = 0; i < k; ++i) {
570 for (i = 0; i < k; ++i) {
571 if (!(funcs[i] = Function::parse(obj1.arrayGet(i, &obj2)))) {
574 if (i > 0 && (funcs[i]->getInputSize() != 1 ||
575 funcs[i]->getOutputSize() != funcs[0]->getOutputSize())) {
576 error(-1, "Incompatible subfunctions in stitching function");
584 if (!dict->lookup("Bounds", &obj1)->isArray() ||
585 obj1.arrayGetLength() != k - 1) {
586 error(-1, "Missing or invalid 'Bounds' entry in stitching function");
589 bounds[0] = domain[0][0];
590 for (i = 1; i < k; ++i) {
591 if (!obj1.arrayGet(i - 1, &obj2)->isNum()) {
592 error(-1, "Invalid type in 'Bounds' array in stitching function");
595 bounds[i] = obj2.getNum();
598 bounds[k] = domain[0][1];
602 if (!dict->lookup("Encode", &obj1)->isArray() ||
603 obj1.arrayGetLength() != 2 * k) {
604 error(-1, "Missing or invalid 'Encode' entry in stitching function");
607 for (i = 0; i < 2 * k; ++i) {
608 if (!obj1.arrayGet(i, &obj2)->isNum()) {
609 error(-1, "Invalid type in 'Encode' array in stitching function");
612 encode[i] = obj2.getNum();
626 StitchingFunction::StitchingFunction(StitchingFunction *func) {
628 funcs = (Function **)gmalloc(k * sizeof(Function *));
629 memcpy(funcs, func->funcs, k * sizeof(Function *));
630 bounds = (double *)gmalloc((k + 1) * sizeof(double));
631 memcpy(bounds, func->bounds, (k + 1) * sizeof(double));
632 encode = (double *)gmalloc(2 * k * sizeof(double));
633 memcpy(encode, func->encode, 2 * k * sizeof(double));
637 StitchingFunction::~StitchingFunction() {
640 for (i = 0; i < k; ++i) {
650 void StitchingFunction::transform(double *in, double *out) {
654 if (in[0] < domain[0][0]) {
656 } else if (in[0] > domain[0][1]) {
661 for (i = 0; i < k - 1; ++i) {
662 if (x < bounds[i+1]) {
666 x = encode[2*i] + ((x - bounds[i]) / (bounds[i+1] - bounds[i])) *
667 (encode[2*i+1] - encode[2*i]);
668 funcs[i]->transform(&x, out);
671 //------------------------------------------------------------------------
672 // PostScriptFunction
673 //------------------------------------------------------------------------
721 // Note: 'if' and 'ifelse' are parsed separately.
722 // The rest are listed here in alphabetical order.
723 // The index in this table is equivalent to the entry in PSOp.
724 char *psOpNames[] = {
767 #define nPSOps (sizeof(psOpNames) / sizeof(char *))
777 // In the code array, 'if'/'ifelse' operators take up three slots
778 // plus space for the code in the subclause(s).
780 // +---------------------------------+
781 // | psOperator: psOpIf / psOpIfelse |
782 // +---------------------------------+
783 // | psBlock: ptr=<A> |
784 // +---------------------------------+
785 // | psBlock: ptr=<B> |
786 // +---------------------------------+
789 // | psOperator: psOpReturn |
790 // +---------------------------------+
791 // <A> | else clause |
793 // | psOperator: psOpReturn |
794 // +---------------------------------+
797 // For 'if', pointer <A> is present in the code stream but unused.
802 GBool booln; // boolean (stack only)
803 int intg; // integer (stack and code)
804 double real; // real (stack and code)
805 PSOp op; // operator (code only)
806 int blk; // if/ifelse block pointer (code only)
810 #define psStackSize 100
815 PSStack() { sp = psStackSize; }
816 void pushBool(GBool booln);
817 void pushInt(int intg);
818 void pushReal(double real);
822 GBool empty() { return sp == psStackSize; }
823 GBool topIsInt() { return sp < psStackSize && stack[sp].type == psInt; }
824 GBool topTwoAreInts()
825 { return sp < psStackSize - 1 &&
826 stack[sp].type == psInt &&
827 stack[sp+1].type == psInt; }
828 GBool topIsReal() { return sp < psStackSize && stack[sp].type == psReal; }
829 GBool topTwoAreNums()
830 { return sp < psStackSize - 1 &&
831 (stack[sp].type == psInt || stack[sp].type == psReal) &&
832 (stack[sp+1].type == psInt || stack[sp+1].type == psReal); }
834 void roll(int n, int j);
840 GBool checkOverflow(int n = 1);
841 GBool checkUnderflow();
842 GBool checkType(PSObjectType t1, PSObjectType t2);
844 PSObject stack[psStackSize];
848 GBool PSStack::checkOverflow(int n) {
850 error(-1, "Stack overflow in PostScript function");
856 GBool PSStack::checkUnderflow() {
857 if (sp == psStackSize) {
858 error(-1, "Stack underflow in PostScript function");
864 GBool PSStack::checkType(PSObjectType t1, PSObjectType t2) {
865 if (stack[sp].type != t1 && stack[sp].type != t2) {
866 error(-1, "Type mismatch in PostScript function");
872 void PSStack::pushBool(GBool booln) {
873 if (checkOverflow()) {
874 stack[--sp].type = psBool;
875 stack[sp].booln = booln;
879 void PSStack::pushInt(int intg) {
880 if (checkOverflow()) {
881 stack[--sp].type = psInt;
882 stack[sp].intg = intg;
886 void PSStack::pushReal(double real) {
887 if (checkOverflow()) {
888 stack[--sp].type = psReal;
889 stack[sp].real = real;
893 GBool PSStack::popBool() {
894 if (checkUnderflow() && checkType(psBool, psBool)) {
895 return stack[sp++].booln;
900 int PSStack::popInt() {
901 if (checkUnderflow() && checkType(psInt, psInt)) {
902 return stack[sp++].intg;
907 double PSStack::popNum() {
910 if (checkUnderflow() && checkType(psInt, psReal)) {
911 ret = (stack[sp].type == psInt) ? (double)stack[sp].intg : stack[sp].real;
918 void PSStack::copy(int n) {
921 if (!checkOverflow(n)) {
924 for (i = sp + n - 1; i <= sp; ++i) {
925 stack[i - n] = stack[i];
930 void PSStack::roll(int n, int j) {
942 if (n <= 0 || j == 0) {
945 for (i = 0; i < j; ++i) {
947 for (k = sp; k < sp + n - 1; ++k) {
948 stack[k] = stack[k+1];
950 stack[sp + n - 1] = obj;
954 void PSStack::index(int i) {
955 if (!checkOverflow()) {
959 stack[sp] = stack[sp + 1 + i];
962 void PSStack::pop() {
963 if (!checkUnderflow()) {
969 PostScriptFunction::PostScriptFunction(Object *funcObj, Dict *dict) {
978 //----- initialize the generic stuff
983 error(-1, "Type 4 function is missing range");
987 //----- get the stream
988 if (!funcObj->isStream()) {
989 error(-1, "Type 4 function isn't a stream");
992 str = funcObj->getStream();
994 //----- parse the function
996 if (!(tok = getToken(str)) || tok->cmp("{")) {
997 error(-1, "Expected '{' at start of PostScript function");
1005 if (!parseCode(str, &codePtr)) {
1018 PostScriptFunction::PostScriptFunction(PostScriptFunction *func) {
1019 memcpy(this, func, sizeof(PostScriptFunction));
1020 code = (PSObject *)gmalloc(codeSize * sizeof(PSObject));
1021 memcpy(code, func->code, codeSize * sizeof(PSObject));
1024 PostScriptFunction::~PostScriptFunction() {
1028 void PostScriptFunction::transform(double *in, double *out) {
1032 stack = new PSStack();
1033 for (i = 0; i < m; ++i) {
1034 //~ may need to check for integers here
1035 stack->pushReal(in[i]);
1038 for (i = n - 1; i >= 0; --i) {
1039 out[i] = stack->popNum();
1040 if (out[i] < range[i][0]) {
1041 out[i] = range[i][0];
1042 } else if (out[i] > range[i][1]) {
1043 out[i] = range[i][1];
1046 // if (!stack->empty()) {
1047 // error(-1, "Extra values on stack at end of PostScript function");
1052 GBool PostScriptFunction::parseCode(Stream *str, int *codePtr) {
1060 if (!(tok = getToken(str))) {
1061 error(-1, "Unexpected end of PostScript function stream");
1064 p = tok->getCString();
1065 if (isdigit(*p) || *p == '.' || *p == '-') {
1067 for (++p; *p; ++p) {
1073 resizeCode(*codePtr);
1075 code[*codePtr].type = psReal;
1077 char *theLocale = setlocale(LC_NUMERIC, "C");
1078 code[*codePtr].real = atof(tok->getCString());
1079 setlocale(LC_NUMERIC, theLocale);
1082 code[*codePtr].type = psInt;
1083 code[*codePtr].intg = atoi(tok->getCString());
1087 } else if (!tok->cmp("{")) {
1091 resizeCode(opPtr + 2);
1092 if (!parseCode(str, codePtr)) {
1095 if (!(tok = getToken(str))) {
1096 error(-1, "Unexpected end of PostScript function stream");
1099 if (!tok->cmp("{")) {
1101 if (!parseCode(str, codePtr)) {
1105 if (!(tok = getToken(str))) {
1106 error(-1, "Unexpected end of PostScript function stream");
1112 if (!tok->cmp("if")) {
1114 error(-1, "Got 'if' operator with two blocks in PostScript function");
1117 code[opPtr].type = psOperator;
1118 code[opPtr].op = psOpIf;
1119 code[opPtr+2].type = psBlock;
1120 code[opPtr+2].blk = *codePtr;
1121 } else if (!tok->cmp("ifelse")) {
1123 error(-1, "Got 'ifelse' operator with one blocks in PostScript function");
1126 code[opPtr].type = psOperator;
1127 code[opPtr].op = psOpIfelse;
1128 code[opPtr+1].type = psBlock;
1129 code[opPtr+1].blk = elsePtr;
1130 code[opPtr+2].type = psBlock;
1131 code[opPtr+2].blk = *codePtr;
1133 error(-1, "Expected if/ifelse operator in PostScript function");
1138 } else if (!tok->cmp("}")) {
1140 resizeCode(*codePtr);
1141 code[*codePtr].type = psOperator;
1142 code[*codePtr].op = psOpReturn;
1148 // invariant: psOpNames[a] < tok < psOpNames[b]
1151 cmp = tok->cmp(psOpNames[mid]);
1154 } else if (cmp < 0) {
1161 error(-1, "Unknown operator '%s' in PostScript function",
1167 resizeCode(*codePtr);
1168 code[*codePtr].type = psOperator;
1169 code[*codePtr].op = (PSOp)a;
1176 GString *PostScriptFunction::getToken(Stream *str) {
1183 } while (c != EOF && isspace(c));
1184 if (c == '{' || c == '}') {
1186 } else if (isdigit(c) || c == '.' || c == '-') {
1189 c = str->lookChar();
1190 if (c == EOF || !(isdigit(c) || c == '.' || c == '-')) {
1198 c = str->lookChar();
1199 if (c == EOF || !isalnum(c)) {
1208 void PostScriptFunction::resizeCode(int newSize) {
1209 if (newSize >= codeSize) {
1211 code = (PSObject *)grealloc(code, codeSize * sizeof(PSObject));
1215 void PostScriptFunction::exec(PSStack *stack, int codePtr) {
1221 switch (code[codePtr].type) {
1223 stack->pushInt(code[codePtr++].intg);
1226 stack->pushReal(code[codePtr++].real);
1229 switch (code[codePtr++].op) {
1231 if (stack->topIsInt()) {
1232 stack->pushInt(abs(stack->popInt()));
1234 stack->pushReal(fabs(stack->popNum()));
1238 if (stack->topTwoAreInts()) {
1239 i2 = stack->popInt();
1240 i1 = stack->popInt();
1241 stack->pushInt(i1 + i2);
1243 r2 = stack->popNum();
1244 r1 = stack->popNum();
1245 stack->pushReal(r1 + r2);
1249 if (stack->topTwoAreInts()) {
1250 i2 = stack->popInt();
1251 i1 = stack->popInt();
1252 stack->pushInt(i1 & i2);
1254 b2 = stack->popBool();
1255 b1 = stack->popBool();
1256 stack->pushReal(b1 && b2);
1260 r2 = stack->popNum();
1261 r1 = stack->popNum();
1262 stack->pushReal(atan2(r1, r2));
1265 i2 = stack->popInt();
1266 i1 = stack->popInt();
1268 stack->pushInt(i1 << i2);
1269 } else if (i2 < 0) {
1270 stack->pushInt((int)((Guint)i1 >> i2));
1276 if (!stack->topIsInt()) {
1277 stack->pushReal(ceil(stack->popNum()));
1281 stack->copy(stack->popInt());
1284 stack->pushReal(cos(stack->popNum()));
1287 if (!stack->topIsInt()) {
1288 stack->pushInt((int)stack->popNum());
1292 if (!stack->topIsReal()) {
1293 stack->pushReal(stack->popNum());
1297 r2 = stack->popNum();
1298 r1 = stack->popNum();
1299 stack->pushReal(r1 / r2);
1305 if (stack->topTwoAreInts()) {
1306 i2 = stack->popInt();
1307 i1 = stack->popInt();
1308 stack->pushBool(i1 == i2);
1309 } else if (stack->topTwoAreNums()) {
1310 r2 = stack->popNum();
1311 r1 = stack->popNum();
1312 stack->pushBool(r1 == r2);
1314 b2 = stack->popBool();
1315 b1 = stack->popBool();
1316 stack->pushBool(b1 == b2);
1323 r2 = stack->popInt();
1324 r1 = stack->popInt();
1325 stack->pushReal(pow(r1, r2));
1328 stack->pushBool(gFalse);
1331 if (!stack->topIsInt()) {
1332 stack->pushReal(floor(stack->popNum()));
1336 if (stack->topTwoAreInts()) {
1337 i2 = stack->popInt();
1338 i1 = stack->popInt();
1339 stack->pushBool(i1 >= i2);
1341 r2 = stack->popNum();
1342 r1 = stack->popNum();
1343 stack->pushBool(r1 >= r2);
1347 if (stack->topTwoAreInts()) {
1348 i2 = stack->popInt();
1349 i1 = stack->popInt();
1350 stack->pushBool(i1 > i2);
1352 r2 = stack->popNum();
1353 r1 = stack->popNum();
1354 stack->pushBool(r1 > r2);
1358 i2 = stack->popInt();
1359 i1 = stack->popInt();
1360 stack->pushInt(i1 / i2);
1363 stack->index(stack->popInt());
1366 if (stack->topTwoAreInts()) {
1367 i2 = stack->popInt();
1368 i1 = stack->popInt();
1369 stack->pushBool(i1 <= i2);
1371 r2 = stack->popNum();
1372 r1 = stack->popNum();
1373 stack->pushBool(r1 <= r2);
1377 stack->pushReal(log(stack->popNum()));
1380 stack->pushReal(log10(stack->popNum()));
1383 if (stack->topTwoAreInts()) {
1384 i2 = stack->popInt();
1385 i1 = stack->popInt();
1386 stack->pushBool(i1 < i2);
1388 r2 = stack->popNum();
1389 r1 = stack->popNum();
1390 stack->pushBool(r1 < r2);
1394 i2 = stack->popInt();
1395 i1 = stack->popInt();
1396 stack->pushInt(i1 % i2);
1399 if (stack->topTwoAreInts()) {
1400 i2 = stack->popInt();
1401 i1 = stack->popInt();
1402 //~ should check for out-of-range, and push a real instead
1403 stack->pushInt(i1 * i2);
1405 r2 = stack->popNum();
1406 r1 = stack->popNum();
1407 stack->pushReal(r1 * r2);
1411 if (stack->topTwoAreInts()) {
1412 i2 = stack->popInt();
1413 i1 = stack->popInt();
1414 stack->pushBool(i1 != i2);
1415 } else if (stack->topTwoAreNums()) {
1416 r2 = stack->popNum();
1417 r1 = stack->popNum();
1418 stack->pushBool(r1 != r2);
1420 b2 = stack->popBool();
1421 b1 = stack->popBool();
1422 stack->pushBool(b1 != b2);
1426 if (stack->topIsInt()) {
1427 stack->pushInt(-stack->popInt());
1429 stack->pushReal(-stack->popNum());
1433 if (stack->topIsInt()) {
1434 stack->pushInt(~stack->popInt());
1436 stack->pushReal(!stack->popBool());
1440 if (stack->topTwoAreInts()) {
1441 i2 = stack->popInt();
1442 i1 = stack->popInt();
1443 stack->pushInt(i1 | i2);
1445 b2 = stack->popBool();
1446 b1 = stack->popBool();
1447 stack->pushReal(b1 || b2);
1454 i2 = stack->popInt();
1455 i1 = stack->popInt();
1456 stack->roll(i1, i2);
1459 if (!stack->topIsInt()) {
1460 r1 = stack->popNum();
1461 stack->pushReal((r1 >= 0) ? floor(r1 + 0.5) : ceil(r1 - 0.5));
1465 stack->pushReal(cos(stack->popNum()));
1468 stack->pushReal(sqrt(stack->popNum()));
1471 if (stack->topTwoAreInts()) {
1472 i2 = stack->popInt();
1473 i1 = stack->popInt();
1474 stack->pushInt(i1 - i2);
1476 r2 = stack->popNum();
1477 r1 = stack->popNum();
1478 stack->pushReal(r1 - r2);
1482 stack->pushBool(gTrue);
1485 if (!stack->topIsInt()) {
1486 r1 = stack->popNum();
1487 stack->pushReal((r1 >= 0) ? floor(r1) : ceil(r1));
1491 if (stack->topTwoAreInts()) {
1492 i2 = stack->popInt();
1493 i1 = stack->popInt();
1494 stack->pushInt(i1 ^ i2);
1496 b2 = stack->popBool();
1497 b1 = stack->popBool();
1498 stack->pushReal(b1 ^ b2);
1502 b1 = stack->popBool();
1504 exec(stack, codePtr + 2);
1506 codePtr = code[codePtr + 1].blk;
1509 b1 = stack->popBool();
1511 exec(stack, codePtr + 2);
1513 exec(stack, code[codePtr].blk);
1515 codePtr = code[codePtr + 1].blk;
1522 error(-1, "Internal: bad object in PostScript function code");