1 //========================================================================
5 // Copyright 2001-2003 Glyph & Cog, LLC
7 //========================================================================
11 #ifdef USE_GCC_PRAGMAS
12 #pragma implementation
26 //------------------------------------------------------------------------
28 //------------------------------------------------------------------------
30 Function::Function() {
33 Function::~Function() {
36 Function *Function::parse(Object *funcObj) {
42 if (funcObj->isStream()) {
43 dict = funcObj->streamGetDict();
44 } else if (funcObj->isDict()) {
45 dict = funcObj->getDict();
46 } else if (funcObj->isName("Identity")) {
47 return new IdentityFunction();
49 error(-1, "Expected function dictionary or stream");
53 if (!dict->lookup("FunctionType", &obj1)->isInt()) {
54 error(-1, "Function type is missing or wrong type");
58 funcType = obj1.getInt();
62 func = new SampledFunction(funcObj, dict);
63 } else if (funcType == 2) {
64 func = new ExponentialFunction(funcObj, dict);
65 } else if (funcType == 3) {
66 func = new StitchingFunction(funcObj, dict);
67 } else if (funcType == 4) {
68 func = new PostScriptFunction(funcObj, dict);
70 error(-1, "Unimplemented function type (%d)", funcType);
81 GBool Function::init(Dict *dict) {
86 if (!dict->lookup("Domain", &obj1)->isArray()) {
87 error(-1, "Function is missing domain");
90 m = obj1.arrayGetLength() / 2;
91 if (m > funcMaxInputs) {
92 error(-1, "Functions with more than %d inputs are unsupported",
96 for (i = 0; i < m; ++i) {
97 obj1.arrayGet(2*i, &obj2);
99 error(-1, "Illegal value in function domain array");
102 domain[i][0] = obj2.getNum();
104 obj1.arrayGet(2*i+1, &obj2);
106 error(-1, "Illegal value in function domain array");
109 domain[i][1] = obj2.getNum();
117 if (dict->lookup("Range", &obj1)->isArray()) {
119 n = obj1.arrayGetLength() / 2;
120 if (n > funcMaxOutputs) {
121 error(-1, "Functions with more than %d outputs are unsupported",
125 for (i = 0; i < n; ++i) {
126 obj1.arrayGet(2*i, &obj2);
128 error(-1, "Illegal value in function range array");
131 range[i][0] = obj2.getNum();
133 obj1.arrayGet(2*i+1, &obj2);
135 error(-1, "Illegal value in function range array");
138 range[i][1] = obj2.getNum();
153 //------------------------------------------------------------------------
155 //------------------------------------------------------------------------
157 IdentityFunction::IdentityFunction() {
160 // fill these in with arbitrary values just in case they get used
164 for (i = 0; i < funcMaxInputs; ++i) {
171 IdentityFunction::~IdentityFunction() {
174 void IdentityFunction::transform(double *in, double *out) {
177 for (i = 0; i < funcMaxOutputs; ++i) {
182 //------------------------------------------------------------------------
184 //------------------------------------------------------------------------
186 SampledFunction::SampledFunction(Object *funcObj, Dict *dict) {
199 //----- initialize the generic stuff
204 error(-1, "Type 0 function is missing range");
208 //----- get the stream
209 if (!funcObj->isStream()) {
210 error(-1, "Type 0 function isn't a stream");
213 str = funcObj->getStream();
216 if (!dict->lookup("Size", &obj1)->isArray() ||
217 obj1.arrayGetLength() != m) {
218 error(-1, "Function has missing or invalid size array");
221 for (i = 0; i < m; ++i) {
222 obj1.arrayGet(i, &obj2);
224 error(-1, "Illegal value in function size array");
227 sampleSize[i] = obj2.getInt();
232 for (i = 1; i < m; ++i) {
233 idxMul[i] = idxMul[i-1] * sampleSize[i-1];
236 //----- BitsPerSample
237 if (!dict->lookup("BitsPerSample", &obj1)->isInt()) {
238 error(-1, "Function has missing or invalid BitsPerSample");
241 sampleBits = obj1.getInt();
242 sampleMul = 1.0 / (double)((1 << sampleBits) - 1);
246 if (dict->lookup("Encode", &obj1)->isArray() &&
247 obj1.arrayGetLength() == 2*m) {
248 for (i = 0; i < m; ++i) {
249 obj1.arrayGet(2*i, &obj2);
251 error(-1, "Illegal value in function encode array");
254 encode[i][0] = obj2.getNum();
256 obj1.arrayGet(2*i+1, &obj2);
258 error(-1, "Illegal value in function encode array");
261 encode[i][1] = obj2.getNum();
265 for (i = 0; i < m; ++i) {
267 encode[i][1] = sampleSize[i] - 1;
271 for (i = 0; i < m; ++i) {
272 inputMul[i] = (encode[i][1] - encode[i][0]) /
273 (domain[i][1] - domain[i][0]);
277 if (dict->lookup("Decode", &obj1)->isArray() &&
278 obj1.arrayGetLength() == 2*n) {
279 for (i = 0; i < n; ++i) {
280 obj1.arrayGet(2*i, &obj2);
282 error(-1, "Illegal value in function decode array");
285 decode[i][0] = obj2.getNum();
287 obj1.arrayGet(2*i+1, &obj2);
289 error(-1, "Illegal value in function decode array");
292 decode[i][1] = obj2.getNum();
296 for (i = 0; i < n; ++i) {
297 decode[i][0] = range[i][0];
298 decode[i][1] = range[i][1];
305 for (i = 0; i < m; ++i)
306 nSamples *= sampleSize[i];
307 samples = (double *)gmallocn(nSamples, sizeof(double));
310 bitMask = (1 << sampleBits) - 1;
312 for (i = 0; i < nSamples; ++i) {
313 if (sampleBits == 8) {
315 } else if (sampleBits == 16) {
317 s = (s << 8) + str->getChar();
318 } else if (sampleBits == 32) {
320 s = (s << 8) + str->getChar();
321 s = (s << 8) + str->getChar();
322 s = (s << 8) + str->getChar();
324 while (bits < sampleBits) {
325 buf = (buf << 8) | (str->getChar() & 0xff);
328 s = (buf >> (bits - sampleBits)) & bitMask;
331 samples[i] = (double)s * sampleMul;
346 SampledFunction::~SampledFunction() {
352 SampledFunction::SampledFunction(SampledFunction *func) {
353 memcpy(this, func, sizeof(SampledFunction));
354 samples = (double *)gmallocn(nSamples, sizeof(double));
355 memcpy(samples, func->samples, nSamples * sizeof(double));
358 void SampledFunction::transform(double *in, double *out) {
360 int e[funcMaxInputs][2];
361 double efrac0[funcMaxInputs];
362 double efrac1[funcMaxInputs];
363 double s[1 << funcMaxInputs];
366 // map input values into sample array
367 for (i = 0; i < m; ++i) {
368 x = (in[i] - domain[i][0]) * inputMul[i] + encode[i][0];
371 } else if (x > sampleSize[i] - 1) {
372 x = sampleSize[i] - 1;
375 if ((e[i][1] = e[i][0] + 1) >= sampleSize[i]) {
376 // this happens if in[i] = domain[i][1]
379 efrac1[i] = x - e[i][0];
380 efrac0[i] = 1 - efrac1[i];
383 // for each output, do m-linear interpolation
384 for (i = 0; i < n; ++i) {
386 // pull 2^m values out of the sample array
387 for (j = 0; j < (1<<m); ++j) {
389 for (k = 0, t = j; k < m; ++k, t >>= 1) {
390 idx += idxMul[k] * (e[k][t & 1]);
395 // do m sets of interpolations
396 for (j = 0, t = (1<<m); j < m; ++j, t >>= 1) {
397 for (k = 0; k < t; k += 2) {
398 s[k >> 1] = efrac0[j] * s[k] + efrac1[j] * s[k+1];
402 // map output value to range
403 out[i] = s[0] * (decode[i][1] - decode[i][0]) + decode[i][0];
404 if (out[i] < range[i][0]) {
405 out[i] = range[i][0];
406 } else if (out[i] > range[i][1]) {
407 out[i] = range[i][1];
412 //------------------------------------------------------------------------
413 // ExponentialFunction
414 //------------------------------------------------------------------------
416 ExponentialFunction::ExponentialFunction(Object *funcObj, Dict *dict) {
422 //----- initialize the generic stuff
427 error(-1, "Exponential function with more than one input");
432 if (dict->lookup("C0", &obj1)->isArray()) {
433 if (hasRange && obj1.arrayGetLength() != n) {
434 error(-1, "Function's C0 array is wrong length");
437 n = obj1.arrayGetLength();
438 for (i = 0; i < n; ++i) {
439 obj1.arrayGet(i, &obj2);
441 error(-1, "Illegal value in function C0 array");
444 c0[i] = obj2.getNum();
448 if (hasRange && n != 1) {
449 error(-1, "Function's C0 array is wrong length");
458 if (dict->lookup("C1", &obj1)->isArray()) {
459 if (obj1.arrayGetLength() != n) {
460 error(-1, "Function's C1 array is wrong length");
463 for (i = 0; i < n; ++i) {
464 obj1.arrayGet(i, &obj2);
466 error(-1, "Illegal value in function C1 array");
469 c1[i] = obj2.getNum();
474 error(-1, "Function's C1 array is wrong length");
482 if (!dict->lookup("N", &obj1)->isNum()) {
483 error(-1, "Function has missing or invalid N");
500 ExponentialFunction::~ExponentialFunction() {
503 ExponentialFunction::ExponentialFunction(ExponentialFunction *func) {
504 memcpy(this, func, sizeof(ExponentialFunction));
507 void ExponentialFunction::transform(double *in, double *out) {
511 if (in[0] < domain[0][0]) {
513 } else if (in[0] > domain[0][1]) {
518 for (i = 0; i < n; ++i) {
519 out[i] = c0[i] + pow(x, e) * (c1[i] - c0[i]);
521 if (out[i] < range[i][0]) {
522 out[i] = range[i][0];
523 } else if (out[i] > range[i][1]) {
524 out[i] = range[i][1];
531 //------------------------------------------------------------------------
533 //------------------------------------------------------------------------
535 StitchingFunction::StitchingFunction(Object *funcObj, Dict *dict) {
544 //----- initialize the generic stuff
549 error(-1, "Stitching function with more than one input");
554 if (!dict->lookup("Functions", &obj1)->isArray()) {
555 error(-1, "Missing 'Functions' entry in stitching function");
558 k = obj1.arrayGetLength();
559 funcs = (Function **)gmallocn(k, sizeof(Function *));
560 bounds = (double *)gmallocn(k + 1, sizeof(double));
561 encode = (double *)gmallocn(2 * k, sizeof(double));
562 for (i = 0; i < k; ++i) {
565 for (i = 0; i < k; ++i) {
566 if (!(funcs[i] = Function::parse(obj1.arrayGet(i, &obj2)))) {
569 if (i > 0 && (funcs[i]->getInputSize() != 1 ||
570 funcs[i]->getOutputSize() != funcs[0]->getOutputSize())) {
571 error(-1, "Incompatible subfunctions in stitching function");
579 if (!dict->lookup("Bounds", &obj1)->isArray() ||
580 obj1.arrayGetLength() != k - 1) {
581 error(-1, "Missing or invalid 'Bounds' entry in stitching function");
584 bounds[0] = domain[0][0];
585 for (i = 1; i < k; ++i) {
586 if (!obj1.arrayGet(i - 1, &obj2)->isNum()) {
587 error(-1, "Invalid type in 'Bounds' array in stitching function");
590 bounds[i] = obj2.getNum();
593 bounds[k] = domain[0][1];
597 if (!dict->lookup("Encode", &obj1)->isArray() ||
598 obj1.arrayGetLength() != 2 * k) {
599 error(-1, "Missing or invalid 'Encode' entry in stitching function");
602 for (i = 0; i < 2 * k; ++i) {
603 if (!obj1.arrayGet(i, &obj2)->isNum()) {
604 error(-1, "Invalid type in 'Encode' array in stitching function");
607 encode[i] = obj2.getNum();
621 StitchingFunction::StitchingFunction(StitchingFunction *func) {
625 funcs = (Function **)gmallocn(k, sizeof(Function *));
626 for (i = 0; i < k; ++i) {
627 funcs[i] = func->funcs[i]->copy();
629 bounds = (double *)gmallocn(k + 1, sizeof(double));
630 memcpy(bounds, func->bounds, (k + 1) * sizeof(double));
631 encode = (double *)gmallocn(2 * k, sizeof(double));
632 memcpy(encode, func->encode, 2 * k * sizeof(double));
636 StitchingFunction::~StitchingFunction() {
640 for (i = 0; i < k; ++i) {
651 void StitchingFunction::transform(double *in, double *out) {
655 if (in[0] < domain[0][0]) {
657 } else if (in[0] > domain[0][1]) {
662 for (i = 0; i < k - 1; ++i) {
663 if (x < bounds[i+1]) {
667 x = encode[2*i] + ((x - bounds[i]) / (bounds[i+1] - bounds[i])) *
668 (encode[2*i+1] - encode[2*i]);
669 funcs[i]->transform(&x, out);
672 //------------------------------------------------------------------------
673 // PostScriptFunction
674 //------------------------------------------------------------------------
722 // Note: 'if' and 'ifelse' are parsed separately.
723 // The rest are listed here in alphabetical order.
724 // The index in this table is equivalent to the entry in PSOp.
725 char *psOpNames[] = {
768 #define nPSOps (sizeof(psOpNames) / sizeof(char *))
778 // In the code array, 'if'/'ifelse' operators take up three slots
779 // plus space for the code in the subclause(s).
781 // +---------------------------------+
782 // | psOperator: psOpIf / psOpIfelse |
783 // +---------------------------------+
784 // | psBlock: ptr=<A> |
785 // +---------------------------------+
786 // | psBlock: ptr=<B> |
787 // +---------------------------------+
790 // | psOperator: psOpReturn |
791 // +---------------------------------+
792 // <A> | else clause |
794 // | psOperator: psOpReturn |
795 // +---------------------------------+
798 // For 'if', pointer <A> is present in the code stream but unused.
803 GBool booln; // boolean (stack only)
804 int intg; // integer (stack and code)
805 double real; // real (stack and code)
806 PSOp op; // operator (code only)
807 int blk; // if/ifelse block pointer (code only)
811 #define psStackSize 100
816 PSStack() { sp = psStackSize; }
817 void pushBool(GBool booln);
818 void pushInt(int intg);
819 void pushReal(double real);
823 GBool empty() { return sp == psStackSize; }
824 GBool topIsInt() { return sp < psStackSize && stack[sp].type == psInt; }
825 GBool topTwoAreInts()
826 { return sp < psStackSize - 1 &&
827 stack[sp].type == psInt &&
828 stack[sp+1].type == psInt; }
829 GBool topIsReal() { return sp < psStackSize && stack[sp].type == psReal; }
830 GBool topTwoAreNums()
831 { return sp < psStackSize - 1 &&
832 (stack[sp].type == psInt || stack[sp].type == psReal) &&
833 (stack[sp+1].type == psInt || stack[sp+1].type == psReal); }
835 void roll(int n, int j);
841 GBool checkOverflow(int n = 1);
842 GBool checkUnderflow();
843 GBool checkType(PSObjectType t1, PSObjectType t2);
845 PSObject stack[psStackSize];
849 GBool PSStack::checkOverflow(int n) {
851 error(-1, "Stack overflow in PostScript function");
857 GBool PSStack::checkUnderflow() {
858 if (sp == psStackSize) {
859 error(-1, "Stack underflow in PostScript function");
865 GBool PSStack::checkType(PSObjectType t1, PSObjectType t2) {
866 if (stack[sp].type != t1 && stack[sp].type != t2) {
867 error(-1, "Type mismatch in PostScript function");
873 void PSStack::pushBool(GBool booln) {
874 if (checkOverflow()) {
875 stack[--sp].type = psBool;
876 stack[sp].booln = booln;
880 void PSStack::pushInt(int intg) {
881 if (checkOverflow()) {
882 stack[--sp].type = psInt;
883 stack[sp].intg = intg;
887 void PSStack::pushReal(double real) {
888 if (checkOverflow()) {
889 stack[--sp].type = psReal;
890 stack[sp].real = real;
894 GBool PSStack::popBool() {
895 if (checkUnderflow() && checkType(psBool, psBool)) {
896 return stack[sp++].booln;
901 int PSStack::popInt() {
902 if (checkUnderflow() && checkType(psInt, psInt)) {
903 return stack[sp++].intg;
908 double PSStack::popNum() {
911 if (checkUnderflow() && checkType(psInt, psReal)) {
912 ret = (stack[sp].type == psInt) ? (double)stack[sp].intg : stack[sp].real;
919 void PSStack::copy(int n) {
922 if (sp + n > psStackSize) {
923 error(-1, "Stack underflow in PostScript function");
926 if (!checkOverflow(n)) {
929 for (i = sp + n - 1; i >= sp; --i) {
930 stack[i - n] = stack[i];
935 void PSStack::roll(int n, int j) {
947 if (n <= 0 || j == 0) {
950 for (i = 0; i < j; ++i) {
952 for (k = sp; k < sp + n - 1; ++k) {
953 stack[k] = stack[k+1];
955 stack[sp + n - 1] = obj;
959 void PSStack::index(int i) {
960 if (!checkOverflow()) {
964 stack[sp] = stack[sp + 1 + i];
967 void PSStack::pop() {
968 if (!checkUnderflow()) {
974 PostScriptFunction::PostScriptFunction(Object *funcObj, Dict *dict) {
983 //----- initialize the generic stuff
988 error(-1, "Type 4 function is missing range");
992 //----- get the stream
993 if (!funcObj->isStream()) {
994 error(-1, "Type 4 function isn't a stream");
997 str = funcObj->getStream();
999 //----- parse the function
1000 codeString = new GString();
1002 if (!(tok = getToken(str)) || tok->cmp("{")) {
1003 error(-1, "Expected '{' at start of PostScript function");
1011 if (!parseCode(str, &codePtr)) {
1024 PostScriptFunction::PostScriptFunction(PostScriptFunction *func) {
1025 memcpy(this, func, sizeof(PostScriptFunction));
1026 code = (PSObject *)gmallocn(codeSize, sizeof(PSObject));
1027 memcpy(code, func->code, codeSize * sizeof(PSObject));
1028 codeString = func->codeString->copy();
1031 PostScriptFunction::~PostScriptFunction() {
1036 void PostScriptFunction::transform(double *in, double *out) {
1040 stack = new PSStack();
1041 for (i = 0; i < m; ++i) {
1042 //~ may need to check for integers here
1043 stack->pushReal(in[i]);
1046 for (i = n - 1; i >= 0; --i) {
1047 out[i] = stack->popNum();
1048 if (out[i] < range[i][0]) {
1049 out[i] = range[i][0];
1050 } else if (out[i] > range[i][1]) {
1051 out[i] = range[i][1];
1054 // if (!stack->empty()) {
1055 // error(-1, "Extra values on stack at end of PostScript function");
1060 GBool PostScriptFunction::parseCode(Stream *str, int *codePtr) {
1068 if (!(tok = getToken(str))) {
1069 error(-1, "Unexpected end of PostScript function stream");
1072 p = tok->getCString();
1073 if (isdigit(*p) || *p == '.' || *p == '-') {
1075 for (++p; *p; ++p) {
1081 resizeCode(*codePtr);
1083 code[*codePtr].type = psReal;
1084 code[*codePtr].real = atof(tok->getCString());
1086 code[*codePtr].type = psInt;
1087 code[*codePtr].intg = atoi(tok->getCString());
1091 } else if (!tok->cmp("{")) {
1095 resizeCode(opPtr + 2);
1096 if (!parseCode(str, codePtr)) {
1099 if (!(tok = getToken(str))) {
1100 error(-1, "Unexpected end of PostScript function stream");
1103 if (!tok->cmp("{")) {
1105 if (!parseCode(str, codePtr)) {
1109 if (!(tok = getToken(str))) {
1110 error(-1, "Unexpected end of PostScript function stream");
1116 if (!tok->cmp("if")) {
1118 error(-1, "Got 'if' operator with two blocks in PostScript function");
1121 code[opPtr].type = psOperator;
1122 code[opPtr].op = psOpIf;
1123 code[opPtr+2].type = psBlock;
1124 code[opPtr+2].blk = *codePtr;
1125 } else if (!tok->cmp("ifelse")) {
1127 error(-1, "Got 'ifelse' operator with one blocks in PostScript function");
1130 code[opPtr].type = psOperator;
1131 code[opPtr].op = psOpIfelse;
1132 code[opPtr+1].type = psBlock;
1133 code[opPtr+1].blk = elsePtr;
1134 code[opPtr+2].type = psBlock;
1135 code[opPtr+2].blk = *codePtr;
1137 error(-1, "Expected if/ifelse operator in PostScript function");
1142 } else if (!tok->cmp("}")) {
1144 resizeCode(*codePtr);
1145 code[*codePtr].type = psOperator;
1146 code[*codePtr].op = psOpReturn;
1152 // invariant: psOpNames[a] < tok < psOpNames[b]
1155 cmp = tok->cmp(psOpNames[mid]);
1158 } else if (cmp < 0) {
1165 error(-1, "Unknown operator '%s' in PostScript function",
1171 resizeCode(*codePtr);
1172 code[*codePtr].type = psOperator;
1173 code[*codePtr].op = (PSOp)a;
1180 GString *PostScriptFunction::getToken(Stream *str) {
1188 codeString->append(c);
1190 } while (c != EOF && isspace(c));
1191 if (c == '{' || c == '}') {
1193 } else if (isdigit(c) || c == '.' || c == '-') {
1196 c = str->lookChar();
1197 if (c == EOF || !(isdigit(c) || c == '.' || c == '-')) {
1201 codeString->append(c);
1206 c = str->lookChar();
1207 if (c == EOF || !isalnum(c)) {
1211 codeString->append(c);
1217 void PostScriptFunction::resizeCode(int newSize) {
1218 if (newSize >= codeSize) {
1220 code = (PSObject *)greallocn(code, codeSize, sizeof(PSObject));
1224 void PostScriptFunction::exec(PSStack *stack, int codePtr) {
1230 switch (code[codePtr].type) {
1232 stack->pushInt(code[codePtr++].intg);
1235 stack->pushReal(code[codePtr++].real);
1238 switch (code[codePtr++].op) {
1240 if (stack->topIsInt()) {
1241 stack->pushInt(abs(stack->popInt()));
1243 stack->pushReal(fabs(stack->popNum()));
1247 if (stack->topTwoAreInts()) {
1248 i2 = stack->popInt();
1249 i1 = stack->popInt();
1250 stack->pushInt(i1 + i2);
1252 r2 = stack->popNum();
1253 r1 = stack->popNum();
1254 stack->pushReal(r1 + r2);
1258 if (stack->topTwoAreInts()) {
1259 i2 = stack->popInt();
1260 i1 = stack->popInt();
1261 stack->pushInt(i1 & i2);
1263 b2 = stack->popBool();
1264 b1 = stack->popBool();
1265 stack->pushBool(b1 && b2);
1269 r2 = stack->popNum();
1270 r1 = stack->popNum();
1271 stack->pushReal(atan2(r1, r2));
1274 i2 = stack->popInt();
1275 i1 = stack->popInt();
1277 stack->pushInt(i1 << i2);
1278 } else if (i2 < 0) {
1279 stack->pushInt((int)((Guint)i1 >> i2));
1285 if (!stack->topIsInt()) {
1286 stack->pushReal(ceil(stack->popNum()));
1290 stack->copy(stack->popInt());
1293 stack->pushReal(cos(stack->popNum()));
1296 if (!stack->topIsInt()) {
1297 stack->pushInt((int)stack->popNum());
1301 if (!stack->topIsReal()) {
1302 stack->pushReal(stack->popNum());
1306 r2 = stack->popNum();
1307 r1 = stack->popNum();
1308 stack->pushReal(r1 / r2);
1314 if (stack->topTwoAreInts()) {
1315 i2 = stack->popInt();
1316 i1 = stack->popInt();
1317 stack->pushBool(i1 == i2);
1318 } else if (stack->topTwoAreNums()) {
1319 r2 = stack->popNum();
1320 r1 = stack->popNum();
1321 stack->pushBool(r1 == r2);
1323 b2 = stack->popBool();
1324 b1 = stack->popBool();
1325 stack->pushBool(b1 == b2);
1332 r2 = stack->popNum();
1333 r1 = stack->popNum();
1334 stack->pushReal(pow(r1, r2));
1337 stack->pushBool(gFalse);
1340 if (!stack->topIsInt()) {
1341 stack->pushReal(floor(stack->popNum()));
1345 if (stack->topTwoAreInts()) {
1346 i2 = stack->popInt();
1347 i1 = stack->popInt();
1348 stack->pushBool(i1 >= i2);
1350 r2 = stack->popNum();
1351 r1 = stack->popNum();
1352 stack->pushBool(r1 >= r2);
1356 if (stack->topTwoAreInts()) {
1357 i2 = stack->popInt();
1358 i1 = stack->popInt();
1359 stack->pushBool(i1 > i2);
1361 r2 = stack->popNum();
1362 r1 = stack->popNum();
1363 stack->pushBool(r1 > r2);
1367 i2 = stack->popInt();
1368 i1 = stack->popInt();
1369 stack->pushInt(i1 / i2);
1372 stack->index(stack->popInt());
1375 if (stack->topTwoAreInts()) {
1376 i2 = stack->popInt();
1377 i1 = stack->popInt();
1378 stack->pushBool(i1 <= i2);
1380 r2 = stack->popNum();
1381 r1 = stack->popNum();
1382 stack->pushBool(r1 <= r2);
1386 stack->pushReal(log(stack->popNum()));
1389 stack->pushReal(log10(stack->popNum()));
1392 if (stack->topTwoAreInts()) {
1393 i2 = stack->popInt();
1394 i1 = stack->popInt();
1395 stack->pushBool(i1 < i2);
1397 r2 = stack->popNum();
1398 r1 = stack->popNum();
1399 stack->pushBool(r1 < r2);
1403 i2 = stack->popInt();
1404 i1 = stack->popInt();
1405 stack->pushInt(i1 % i2);
1408 if (stack->topTwoAreInts()) {
1409 i2 = stack->popInt();
1410 i1 = stack->popInt();
1411 //~ should check for out-of-range, and push a real instead
1412 stack->pushInt(i1 * i2);
1414 r2 = stack->popNum();
1415 r1 = stack->popNum();
1416 stack->pushReal(r1 * r2);
1420 if (stack->topTwoAreInts()) {
1421 i2 = stack->popInt();
1422 i1 = stack->popInt();
1423 stack->pushBool(i1 != i2);
1424 } else if (stack->topTwoAreNums()) {
1425 r2 = stack->popNum();
1426 r1 = stack->popNum();
1427 stack->pushBool(r1 != r2);
1429 b2 = stack->popBool();
1430 b1 = stack->popBool();
1431 stack->pushBool(b1 != b2);
1435 if (stack->topIsInt()) {
1436 stack->pushInt(-stack->popInt());
1438 stack->pushReal(-stack->popNum());
1442 if (stack->topIsInt()) {
1443 stack->pushInt(~stack->popInt());
1445 stack->pushBool(!stack->popBool());
1449 if (stack->topTwoAreInts()) {
1450 i2 = stack->popInt();
1451 i1 = stack->popInt();
1452 stack->pushInt(i1 | i2);
1454 b2 = stack->popBool();
1455 b1 = stack->popBool();
1456 stack->pushBool(b1 || b2);
1463 i2 = stack->popInt();
1464 i1 = stack->popInt();
1465 stack->roll(i1, i2);
1468 if (!stack->topIsInt()) {
1469 r1 = stack->popNum();
1470 stack->pushReal((r1 >= 0) ? floor(r1 + 0.5) : ceil(r1 - 0.5));
1474 stack->pushReal(sin(stack->popNum()));
1477 stack->pushReal(sqrt(stack->popNum()));
1480 if (stack->topTwoAreInts()) {
1481 i2 = stack->popInt();
1482 i1 = stack->popInt();
1483 stack->pushInt(i1 - i2);
1485 r2 = stack->popNum();
1486 r1 = stack->popNum();
1487 stack->pushReal(r1 - r2);
1491 stack->pushBool(gTrue);
1494 if (!stack->topIsInt()) {
1495 r1 = stack->popNum();
1496 stack->pushReal((r1 >= 0) ? floor(r1) : ceil(r1));
1500 if (stack->topTwoAreInts()) {
1501 i2 = stack->popInt();
1502 i1 = stack->popInt();
1503 stack->pushInt(i1 ^ i2);
1505 b2 = stack->popBool();
1506 b1 = stack->popBool();
1507 stack->pushBool(b1 ^ b2);
1511 b1 = stack->popBool();
1513 exec(stack, codePtr + 2);
1515 codePtr = code[codePtr + 1].blk;
1518 b1 = stack->popBool();
1520 exec(stack, codePtr + 2);
1522 exec(stack, code[codePtr].blk);
1524 codePtr = code[codePtr + 1].blk;
1531 error(-1, "Internal: bad object in PostScript function code");