1 //========================================================================
5 // Copyright 2001-2002 Glyph & Cog, LLC
7 //========================================================================
10 #pragma implementation
25 //------------------------------------------------------------------------
27 //------------------------------------------------------------------------
29 Function::Function() {
32 Function::~Function() {
35 Function *Function::parse(Object *funcObj) {
41 if (funcObj->isStream()) {
42 dict = funcObj->streamGetDict();
43 } else if (funcObj->isDict()) {
44 dict = funcObj->getDict();
45 } else if (funcObj->isName("Identity")) {
46 return new IdentityFunction();
48 error(-1, "Expected function dictionary or stream");
52 if (!dict->lookup("FunctionType", &obj1)->isInt()) {
53 error(-1, "Function type is missing or wrong type");
57 funcType = obj1.getInt();
61 func = new SampledFunction(funcObj, dict);
62 } else if (funcType == 2) {
63 func = new ExponentialFunction(funcObj, dict);
64 } else if (funcType == 3) {
65 func = new StitchingFunction(funcObj, dict);
66 } else if (funcType == 4) {
67 func = new PostScriptFunction(funcObj, dict);
69 error(-1, "Unimplemented function type (%d)", funcType);
80 GBool Function::init(Dict *dict) {
85 if (!dict->lookup("Domain", &obj1)->isArray()) {
86 error(-1, "Function is missing domain");
89 m = obj1.arrayGetLength() / 2;
90 if (m > funcMaxInputs) {
91 error(-1, "Functions with more than %d inputs are unsupported",
95 for (i = 0; i < m; ++i) {
96 obj1.arrayGet(2*i, &obj2);
98 error(-1, "Illegal value in function domain array");
101 domain[i][0] = obj2.getNum();
103 obj1.arrayGet(2*i+1, &obj2);
105 error(-1, "Illegal value in function domain array");
108 domain[i][1] = obj2.getNum();
116 if (dict->lookup("Range", &obj1)->isArray()) {
118 n = obj1.arrayGetLength() / 2;
119 if (n > funcMaxOutputs) {
120 error(-1, "Functions with more than %d outputs are unsupported",
124 for (i = 0; i < n; ++i) {
125 obj1.arrayGet(2*i, &obj2);
127 error(-1, "Illegal value in function range array");
130 range[i][0] = obj2.getNum();
132 obj1.arrayGet(2*i+1, &obj2);
134 error(-1, "Illegal value in function range array");
137 range[i][1] = obj2.getNum();
152 //------------------------------------------------------------------------
154 //------------------------------------------------------------------------
156 IdentityFunction::IdentityFunction() {
159 // fill these in with arbitrary values just in case they get used
163 for (i = 0; i < funcMaxInputs; ++i) {
170 IdentityFunction::~IdentityFunction() {
173 void IdentityFunction::transform(double *in, double *out) {
176 for (i = 0; i < funcMaxOutputs; ++i) {
181 //------------------------------------------------------------------------
183 //------------------------------------------------------------------------
185 SampledFunction::SampledFunction(Object *funcObj, Dict *dict) {
187 int nSamples, sampleBits;
198 //----- initialize the generic stuff
203 error(-1, "Type 0 function is missing range");
207 //----- get the stream
208 if (!funcObj->isStream()) {
209 error(-1, "Type 0 function isn't a stream");
212 str = funcObj->getStream();
215 if (!dict->lookup("Size", &obj1)->isArray() ||
216 obj1.arrayGetLength() != m) {
217 error(-1, "Function has missing or invalid size array");
220 for (i = 0; i < m; ++i) {
221 obj1.arrayGet(i, &obj2);
223 error(-1, "Illegal value in function size array");
226 sampleSize[i] = obj2.getInt();
231 //----- BitsPerSample
232 if (!dict->lookup("BitsPerSample", &obj1)->isInt()) {
233 error(-1, "Function has missing or invalid BitsPerSample");
236 sampleBits = obj1.getInt();
237 sampleMul = 1.0 / (double)((1 << sampleBits) - 1);
241 if (dict->lookup("Encode", &obj1)->isArray() &&
242 obj1.arrayGetLength() == 2*m) {
243 for (i = 0; i < m; ++i) {
244 obj1.arrayGet(2*i, &obj2);
246 error(-1, "Illegal value in function encode array");
249 encode[i][0] = obj2.getNum();
251 obj1.arrayGet(2*i+1, &obj2);
253 error(-1, "Illegal value in function encode array");
256 encode[i][1] = obj2.getNum();
260 for (i = 0; i < m; ++i) {
262 encode[i][1] = sampleSize[i] - 1;
268 if (dict->lookup("Decode", &obj1)->isArray() &&
269 obj1.arrayGetLength() == 2*n) {
270 for (i = 0; i < n; ++i) {
271 obj1.arrayGet(2*i, &obj2);
273 error(-1, "Illegal value in function decode array");
276 decode[i][0] = obj2.getNum();
278 obj1.arrayGet(2*i+1, &obj2);
280 error(-1, "Illegal value in function decode array");
283 decode[i][1] = obj2.getNum();
287 for (i = 0; i < n; ++i) {
288 decode[i][0] = range[i][0];
289 decode[i][1] = range[i][1];
296 for (i = 0; i < m; ++i)
297 nSamples *= sampleSize[i];
298 samples = (double *)gmalloc(nSamples * sizeof(double));
301 bitMask = (1 << sampleBits) - 1;
303 for (i = 0; i < nSamples; ++i) {
304 if (sampleBits == 8) {
306 } else if (sampleBits == 16) {
308 s = (s << 8) + str->getChar();
309 } else if (sampleBits == 32) {
311 s = (s << 8) + str->getChar();
312 s = (s << 8) + str->getChar();
313 s = (s << 8) + str->getChar();
315 while (bits < sampleBits) {
316 buf = (buf << 8) | (str->getChar() & 0xff);
319 s = (buf >> (bits - sampleBits)) & bitMask;
322 samples[i] = (double)s * sampleMul;
337 SampledFunction::~SampledFunction() {
343 SampledFunction::SampledFunction(SampledFunction *func) {
346 memcpy(this, func, sizeof(SampledFunction));
349 for (i = 0; i < m; ++i) {
350 nSamples *= sampleSize[i];
352 samples = (double *)gmalloc(nSamples * sizeof(double));
353 memcpy(samples, func->samples, nSamples * sizeof(double));
356 void SampledFunction::transform(double *in, double *out) {
358 int e[2][funcMaxInputs];
359 double efrac[funcMaxInputs];
360 double s0[1 << funcMaxInputs], s1[1 << funcMaxInputs];
363 // map input values into sample array
364 for (i = 0; i < m; ++i) {
365 x = ((in[i] - domain[i][0]) / (domain[i][1] - domain[i][0])) *
366 (encode[i][1] - encode[i][0]) + encode[i][0];
369 } else if (x > sampleSize[i] - 1) {
370 x = sampleSize[i] - 1;
372 e[0][i] = (int)floor(x);
373 e[1][i] = (int)ceil(x);
374 efrac[i] = x - e[0][i];
377 // for each output, do m-linear interpolation
378 for (i = 0; i < n; ++i) {
380 // pull 2^m values out of the sample array
381 for (j = 0; j < (1<<m); ++j) {
382 idx = e[j & 1][m - 1];
383 for (k = m - 2; k >= 0; --k) {
384 idx = idx * sampleSize[k] + e[(j >> k) & 1][k];
387 s0[j] = samples[idx];
390 // do m sets of interpolations
391 for (j = 0; j < m; ++j) {
392 for (k = 0; k < (1 << (m - j)); k += 2) {
393 s1[k >> 1] = (1 - efrac[j]) * s0[k] + efrac[j] * s0[k+1];
395 memcpy(s0, s1, (1 << (m - j - 1)) * sizeof(double));
398 // map output value to range
399 out[i] = s0[0] * (decode[i][1] - decode[i][0]) + decode[i][0];
400 if (out[i] < range[i][0]) {
401 out[i] = range[i][0];
402 } else if (out[i] > range[i][1]) {
403 out[i] = range[i][1];
408 //------------------------------------------------------------------------
409 // ExponentialFunction
410 //------------------------------------------------------------------------
412 ExponentialFunction::ExponentialFunction(Object *funcObj, Dict *dict) {
419 //----- initialize the generic stuff
424 error(-1, "Exponential function with more than one input");
429 //----- default values
430 for (i = 0; i < funcMaxOutputs; ++i) {
436 if (dict->lookup("C0", &obj1)->isArray()) {
438 n = obj1.arrayGetLength();
440 } else if (obj1.arrayGetLength() != n) {
441 error(-1, "Function's C0 array is wrong length");
444 for (i = 0; i < n; ++i) {
445 obj1.arrayGet(i, &obj2);
447 error(-1, "Illegal value in function C0 array");
450 c0[i] = obj2.getNum();
457 if (dict->lookup("C1", &obj1)->isArray()) {
459 n = obj1.arrayGetLength();
461 } else if (obj1.arrayGetLength() != n) {
462 error(-1, "Function's C1 array is wrong length");
465 for (i = 0; i < n; ++i) {
466 obj1.arrayGet(i, &obj2);
468 error(-1, "Illegal value in function C1 array");
471 c1[i] = obj2.getNum();
478 if (!dict->lookup("N", &obj1)->isNum()) {
479 error(-1, "Function has missing or invalid N");
485 // this isn't supposed to happen, but I've run into (broken) PDF
486 // files where it does
488 error(-1, "Exponential function does not define number of output values");
503 ExponentialFunction::~ExponentialFunction() {
506 ExponentialFunction::ExponentialFunction(ExponentialFunction *func) {
507 memcpy(this, func, sizeof(ExponentialFunction));
510 void ExponentialFunction::transform(double *in, double *out) {
514 if (in[0] < domain[0][0]) {
516 } else if (in[0] > domain[0][1]) {
521 for (i = 0; i < n; ++i) {
522 out[i] = c0[i] + pow(x, e) * (c1[i] - c0[i]);
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];
534 //------------------------------------------------------------------------
536 //------------------------------------------------------------------------
538 StitchingFunction::StitchingFunction(Object *funcObj, Dict *dict) {
547 //----- initialize the generic stuff
552 error(-1, "Stitching function with more than one input");
557 if (!dict->lookup("Functions", &obj1)->isArray()) {
558 error(-1, "Missing 'Functions' entry in stitching function");
561 k = obj1.arrayGetLength();
562 funcs = (Function **)gmalloc(k * sizeof(Function *));
563 bounds = (double *)gmalloc((k + 1) * sizeof(double));
564 encode = (double *)gmalloc(2 * k * sizeof(double));
565 for (i = 0; i < k; ++i) {
568 for (i = 0; i < k; ++i) {
569 if (!(funcs[i] = Function::parse(obj1.arrayGet(i, &obj2)))) {
572 if (i > 0 && (funcs[i]->getInputSize() != 1 ||
573 funcs[i]->getOutputSize() != funcs[0]->getOutputSize())) {
574 error(-1, "Incompatible subfunctions in stitching function");
582 if (!dict->lookup("Bounds", &obj1)->isArray() ||
583 obj1.arrayGetLength() != k - 1) {
584 error(-1, "Missing or invalid 'Bounds' entry in stitching function");
587 bounds[0] = domain[0][0];
588 for (i = 1; i < k; ++i) {
589 if (!obj1.arrayGet(i - 1, &obj2)->isNum()) {
590 error(-1, "Invalid type in 'Bounds' array in stitching function");
593 bounds[i] = obj2.getNum();
596 bounds[k] = domain[0][1];
600 if (!dict->lookup("Encode", &obj1)->isArray() ||
601 obj1.arrayGetLength() != 2 * k) {
602 error(-1, "Missing or invalid 'Encode' entry in stitching function");
605 for (i = 0; i < 2 * k; ++i) {
606 if (!obj1.arrayGet(i, &obj2)->isNum()) {
607 error(-1, "Invalid type in 'Encode' array in stitching function");
610 encode[i] = obj2.getNum();
624 StitchingFunction::StitchingFunction(StitchingFunction *func) {
626 funcs = (Function **)gmalloc(k * sizeof(Function *));
627 memcpy(funcs, func->funcs, k * sizeof(Function *));
628 bounds = (double *)gmalloc((k + 1) * sizeof(double));
629 memcpy(bounds, func->bounds, (k + 1) * sizeof(double));
630 encode = (double *)gmalloc(2 * k * sizeof(double));
631 memcpy(encode, func->encode, 2 * k * sizeof(double));
635 StitchingFunction::~StitchingFunction() {
638 for (i = 0; i < k; ++i) {
648 void StitchingFunction::transform(double *in, double *out) {
652 if (in[0] < domain[0][0]) {
654 } else if (in[0] > domain[0][1]) {
659 for (i = 0; i < k - 1; ++i) {
660 if (x < bounds[i+1]) {
664 x = encode[2*i] + ((x - bounds[i]) / (bounds[i+1] - bounds[i])) *
665 (encode[2*i+1] - encode[2*i]);
666 funcs[i]->transform(&x, out);
669 //------------------------------------------------------------------------
670 // PostScriptFunction
671 //------------------------------------------------------------------------
719 // Note: 'if' and 'ifelse' are parsed separately.
720 // The rest are listed here in alphabetical order.
721 // The index in this table is equivalent to the entry in PSOp.
722 char *psOpNames[] = {
765 #define nPSOps (sizeof(psOpNames) / sizeof(char *))
775 // In the code array, 'if'/'ifelse' operators take up three slots
776 // plus space for the code in the subclause(s).
778 // +---------------------------------+
779 // | psOperator: psOpIf / psOpIfelse |
780 // +---------------------------------+
781 // | psBlock: ptr=<A> |
782 // +---------------------------------+
783 // | psBlock: ptr=<B> |
784 // +---------------------------------+
787 // | psOperator: psOpReturn |
788 // +---------------------------------+
789 // <A> | else clause |
791 // | psOperator: psOpReturn |
792 // +---------------------------------+
795 // For 'if', pointer <A> is present in the code stream but unused.
800 GBool booln; // boolean (stack only)
801 int intg; // integer (stack and code)
802 double real; // real (stack and code)
803 PSOp op; // operator (code only)
804 int blk; // if/ifelse block pointer (code only)
808 #define psStackSize 100
813 PSStack() { sp = psStackSize; }
814 void pushBool(GBool booln);
815 void pushInt(int intg);
816 void pushReal(double real);
820 GBool empty() { return sp == psStackSize; }
821 GBool topIsInt() { return sp < psStackSize && stack[sp].type == psInt; }
822 GBool topTwoAreInts()
823 { return sp < psStackSize - 1 &&
824 stack[sp].type == psInt &&
825 stack[sp+1].type == psInt; }
826 GBool topIsReal() { return sp < psStackSize && stack[sp].type == psReal; }
827 GBool topTwoAreNums()
828 { return sp < psStackSize - 1 &&
829 (stack[sp].type == psInt || stack[sp].type == psReal) &&
830 (stack[sp+1].type == psInt || stack[sp+1].type == psReal); }
832 void roll(int n, int j);
838 GBool checkOverflow(int n = 1);
839 GBool checkUnderflow();
840 GBool checkType(PSObjectType t1, PSObjectType t2);
842 PSObject stack[psStackSize];
846 GBool PSStack::checkOverflow(int n) {
848 error(-1, "Stack overflow in PostScript function");
854 GBool PSStack::checkUnderflow() {
855 if (sp == psStackSize) {
856 error(-1, "Stack underflow in PostScript function");
862 GBool PSStack::checkType(PSObjectType t1, PSObjectType t2) {
863 if (stack[sp].type != t1 && stack[sp].type != t2) {
864 error(-1, "Type mismatch in PostScript function");
870 void PSStack::pushBool(GBool booln) {
871 if (checkOverflow()) {
872 stack[--sp].type = psBool;
873 stack[sp].booln = booln;
877 void PSStack::pushInt(int intg) {
878 if (checkOverflow()) {
879 stack[--sp].type = psInt;
880 stack[sp].intg = intg;
884 void PSStack::pushReal(double real) {
885 if (checkOverflow()) {
886 stack[--sp].type = psReal;
887 stack[sp].real = real;
891 GBool PSStack::popBool() {
892 if (checkUnderflow() && checkType(psBool, psBool)) {
893 return stack[sp++].booln;
898 int PSStack::popInt() {
899 if (checkUnderflow() && checkType(psInt, psInt)) {
900 return stack[sp++].intg;
905 double PSStack::popNum() {
908 if (checkUnderflow() && checkType(psInt, psReal)) {
909 ret = (stack[sp].type == psInt) ? (double)stack[sp].intg : stack[sp].real;
916 void PSStack::copy(int n) {
919 if (!checkOverflow(n)) {
922 for (i = sp + n - 1; i <= sp; ++i) {
923 stack[i - n] = stack[i];
928 void PSStack::roll(int n, int j) {
940 if (n <= 0 || j == 0) {
943 for (i = 0; i < j; ++i) {
945 for (k = sp; k < sp + n - 1; ++k) {
946 stack[k] = stack[k+1];
948 stack[sp + n - 1] = obj;
952 void PSStack::index(int i) {
953 if (!checkOverflow()) {
957 stack[sp] = stack[sp + 1 + i];
960 void PSStack::pop() {
961 if (!checkUnderflow()) {
967 PostScriptFunction::PostScriptFunction(Object *funcObj, Dict *dict) {
976 //----- initialize the generic stuff
981 error(-1, "Type 4 function is missing range");
985 //----- get the stream
986 if (!funcObj->isStream()) {
987 error(-1, "Type 4 function isn't a stream");
990 str = funcObj->getStream();
992 //----- parse the function
994 if (!(tok = getToken(str)) || tok->cmp("{")) {
995 error(-1, "Expected '{' at start of PostScript function");
1003 if (!parseCode(str, &codePtr)) {
1016 PostScriptFunction::PostScriptFunction(PostScriptFunction *func) {
1017 memcpy(this, func, sizeof(PostScriptFunction));
1018 code = (PSObject *)gmalloc(codeSize * sizeof(PSObject));
1019 memcpy(code, func->code, codeSize * sizeof(PSObject));
1022 PostScriptFunction::~PostScriptFunction() {
1026 void PostScriptFunction::transform(double *in, double *out) {
1030 stack = new PSStack();
1031 for (i = 0; i < m; ++i) {
1032 //~ may need to check for integers here
1033 stack->pushReal(in[i]);
1036 for (i = n - 1; i >= 0; --i) {
1037 out[i] = stack->popNum();
1038 if (out[i] < range[i][0]) {
1039 out[i] = range[i][0];
1040 } else if (out[i] > range[i][1]) {
1041 out[i] = range[i][1];
1044 // if (!stack->empty()) {
1045 // error(-1, "Extra values on stack at end of PostScript function");
1050 GBool PostScriptFunction::parseCode(Stream *str, int *codePtr) {
1058 if (!(tok = getToken(str))) {
1059 error(-1, "Unexpected end of PostScript function stream");
1062 p = tok->getCString();
1063 if (isdigit(*p) || *p == '.' || *p == '-') {
1065 for (++p; *p; ++p) {
1071 resizeCode(*codePtr);
1073 code[*codePtr].type = psReal;
1074 code[*codePtr].real = atof(tok->getCString());
1076 code[*codePtr].type = psInt;
1077 code[*codePtr].intg = atoi(tok->getCString());
1081 } else if (!tok->cmp("{")) {
1085 resizeCode(opPtr + 2);
1086 if (!parseCode(str, codePtr)) {
1089 if (!(tok = getToken(str))) {
1090 error(-1, "Unexpected end of PostScript function stream");
1093 if (!tok->cmp("{")) {
1095 if (!parseCode(str, codePtr)) {
1102 if (!(tok = getToken(str))) {
1103 error(-1, "Unexpected end of PostScript function stream");
1106 if (!tok->cmp("if")) {
1108 error(-1, "Got 'if' operator with two blocks in PostScript function");
1111 code[opPtr].type = psOperator;
1112 code[opPtr].op = psOpIf;
1113 code[opPtr+2].type = psBlock;
1114 code[opPtr+2].blk = *codePtr;
1115 } else if (!tok->cmp("ifelse")) {
1117 error(-1, "Got 'ifelse' operator with one blocks in PostScript function");
1120 code[opPtr].type = psOperator;
1121 code[opPtr].op = psOpIfelse;
1122 code[opPtr+1].type = psBlock;
1123 code[opPtr+1].blk = elsePtr;
1124 code[opPtr+2].type = psBlock;
1125 code[opPtr+2].blk = *codePtr;
1127 error(-1, "Expected if/ifelse operator in PostScript function");
1132 } else if (!tok->cmp("}")) {
1134 resizeCode(*codePtr);
1135 code[*codePtr].type = psOperator;
1136 code[*codePtr].op = psOpReturn;
1142 // invariant: psOpNames[a] < tok < psOpNames[b]
1145 cmp = tok->cmp(psOpNames[mid]);
1148 } else if (cmp < 0) {
1155 error(-1, "Unknown operator '%s' in PostScript function",
1161 resizeCode(*codePtr);
1162 code[*codePtr].type = psOperator;
1163 code[*codePtr].op = (PSOp)a;
1170 GString *PostScriptFunction::getToken(Stream *str) {
1177 } while (c != EOF && isspace(c));
1178 if (c == '{' || c == '}') {
1180 } else if (isdigit(c) || c == '.' || c == '-') {
1183 c = str->lookChar();
1184 if (c == EOF || !(isdigit(c) || c == '.' || c == '-')) {
1192 c = str->lookChar();
1193 if (c == EOF || !isalnum(c)) {
1202 void PostScriptFunction::resizeCode(int newSize) {
1203 if (newSize >= codeSize) {
1205 code = (PSObject *)grealloc(code, codeSize * sizeof(PSObject));
1209 void PostScriptFunction::exec(PSStack *stack, int codePtr) {
1215 switch (code[codePtr].type) {
1217 stack->pushInt(code[codePtr++].intg);
1220 stack->pushReal(code[codePtr++].real);
1223 switch (code[codePtr++].op) {
1225 if (stack->topIsInt()) {
1226 stack->pushInt(abs(stack->popInt()));
1228 stack->pushReal(fabs(stack->popNum()));
1232 if (stack->topTwoAreInts()) {
1233 i2 = stack->popInt();
1234 i1 = stack->popInt();
1235 stack->pushInt(i1 + i2);
1237 r2 = stack->popNum();
1238 r1 = stack->popNum();
1239 stack->pushReal(r1 + r2);
1243 if (stack->topTwoAreInts()) {
1244 i2 = stack->popInt();
1245 i1 = stack->popInt();
1246 stack->pushInt(i1 & i2);
1248 b2 = stack->popBool();
1249 b1 = stack->popBool();
1250 stack->pushReal(b1 && b2);
1254 r2 = stack->popNum();
1255 r1 = stack->popNum();
1256 stack->pushReal(atan2(r1, r2));
1259 i2 = stack->popInt();
1260 i1 = stack->popInt();
1262 stack->pushInt(i1 << i2);
1263 } else if (i2 < 0) {
1264 stack->pushInt((int)((Guint)i1 >> i2));
1270 if (!stack->topIsInt()) {
1271 stack->pushReal(ceil(stack->popNum()));
1275 stack->copy(stack->popInt());
1278 stack->pushReal(cos(stack->popNum()));
1281 if (!stack->topIsInt()) {
1282 stack->pushInt((int)stack->popNum());
1286 if (!stack->topIsReal()) {
1287 stack->pushReal(stack->popNum());
1291 r2 = stack->popNum();
1292 r1 = stack->popNum();
1293 stack->pushReal(r1 / r2);
1299 if (stack->topTwoAreInts()) {
1300 i2 = stack->popInt();
1301 i1 = stack->popInt();
1302 stack->pushBool(i1 == i2);
1303 } else if (stack->topTwoAreNums()) {
1304 r2 = stack->popNum();
1305 r1 = stack->popNum();
1306 stack->pushBool(r1 == r2);
1308 b2 = stack->popBool();
1309 b1 = stack->popBool();
1310 stack->pushBool(b1 == b2);
1317 r2 = stack->popInt();
1318 r1 = stack->popInt();
1319 stack->pushReal(pow(r1, r2));
1322 stack->pushBool(gFalse);
1325 if (!stack->topIsInt()) {
1326 stack->pushReal(floor(stack->popNum()));
1330 if (stack->topTwoAreInts()) {
1331 i2 = stack->popInt();
1332 i1 = stack->popInt();
1333 stack->pushBool(i1 >= i2);
1335 r2 = stack->popNum();
1336 r1 = stack->popNum();
1337 stack->pushBool(r1 >= r2);
1341 if (stack->topTwoAreInts()) {
1342 i2 = stack->popInt();
1343 i1 = stack->popInt();
1344 stack->pushBool(i1 > i2);
1346 r2 = stack->popNum();
1347 r1 = stack->popNum();
1348 stack->pushBool(r1 > r2);
1352 i2 = stack->popInt();
1353 i1 = stack->popInt();
1354 stack->pushInt(i1 / i2);
1357 stack->index(stack->popInt());
1360 if (stack->topTwoAreInts()) {
1361 i2 = stack->popInt();
1362 i1 = stack->popInt();
1363 stack->pushBool(i1 <= i2);
1365 r2 = stack->popNum();
1366 r1 = stack->popNum();
1367 stack->pushBool(r1 <= r2);
1371 stack->pushReal(log(stack->popNum()));
1374 stack->pushReal(log10(stack->popNum()));
1377 if (stack->topTwoAreInts()) {
1378 i2 = stack->popInt();
1379 i1 = stack->popInt();
1380 stack->pushBool(i1 < i2);
1382 r2 = stack->popNum();
1383 r1 = stack->popNum();
1384 stack->pushBool(r1 < r2);
1388 i2 = stack->popInt();
1389 i1 = stack->popInt();
1390 stack->pushInt(i1 % i2);
1393 if (stack->topTwoAreInts()) {
1394 i2 = stack->popInt();
1395 i1 = stack->popInt();
1396 //~ should check for out-of-range, and push a real instead
1397 stack->pushInt(i1 * i2);
1399 r2 = stack->popNum();
1400 r1 = stack->popNum();
1401 stack->pushReal(r1 * r2);
1405 if (stack->topTwoAreInts()) {
1406 i2 = stack->popInt();
1407 i1 = stack->popInt();
1408 stack->pushBool(i1 != i2);
1409 } else if (stack->topTwoAreNums()) {
1410 r2 = stack->popNum();
1411 r1 = stack->popNum();
1412 stack->pushBool(r1 != r2);
1414 b2 = stack->popBool();
1415 b1 = stack->popBool();
1416 stack->pushBool(b1 != b2);
1420 if (stack->topIsInt()) {
1421 stack->pushInt(-stack->popInt());
1423 stack->pushReal(-stack->popNum());
1427 if (stack->topIsInt()) {
1428 stack->pushInt(~stack->popInt());
1430 stack->pushReal(!stack->popBool());
1434 if (stack->topTwoAreInts()) {
1435 i2 = stack->popInt();
1436 i1 = stack->popInt();
1437 stack->pushInt(i1 | i2);
1439 b2 = stack->popBool();
1440 b1 = stack->popBool();
1441 stack->pushReal(b1 || b2);
1448 i2 = stack->popInt();
1449 i1 = stack->popInt();
1450 stack->roll(i1, i2);
1453 if (!stack->topIsInt()) {
1454 r1 = stack->popNum();
1455 stack->pushReal((r1 >= 0) ? floor(r1 + 0.5) : ceil(r1 - 0.5));
1459 stack->pushReal(cos(stack->popNum()));
1462 stack->pushReal(sqrt(stack->popNum()));
1465 if (stack->topTwoAreInts()) {
1466 i2 = stack->popInt();
1467 i1 = stack->popInt();
1468 stack->pushInt(i1 - i2);
1470 r2 = stack->popNum();
1471 r1 = stack->popNum();
1472 stack->pushReal(r1 - r2);
1476 stack->pushBool(gTrue);
1479 if (!stack->topIsInt()) {
1480 r1 = stack->popNum();
1481 stack->pushReal((r1 >= 0) ? floor(r1) : ceil(r1));
1485 if (stack->topTwoAreInts()) {
1486 i2 = stack->popInt();
1487 i1 = stack->popInt();
1488 stack->pushInt(i1 ^ i2);
1490 b2 = stack->popBool();
1491 b1 = stack->popBool();
1492 stack->pushReal(b1 ^ b2);
1496 b1 = stack->popBool();
1498 exec(stack, codePtr + 2);
1500 codePtr = code[codePtr + 1].blk;
1503 b1 = stack->popBool();
1505 exec(stack, codePtr + 2);
1507 exec(stack, code[codePtr].blk);
1509 codePtr = code[codePtr + 1].blk;
1516 error(-1, "Internal: bad object in PostScript function code");