| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980 | 
							- /* Copyright 2017 Mozilla Foundation
 
-  *
 
-  * Licensed under the Apache License, Version 2.0 (the "License");
 
-  * you may not use this file except in compliance with the License.
 
-  * You may obtain a copy of the License at
 
-  *
 
-  *     http://www.apache.org/licenses/LICENSE-2.0
 
-  *
 
-  * Unless required by applicable law or agreed to in writing, software
 
-  * distributed under the License is distributed on an "AS IS" BASIS,
 
-  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
-  * See the License for the specific language governing permissions and
 
-  * limitations under the License.
 
-  */
 
- 'use strict';
 
- var sharedUtil = require('../shared/util.js');
 
- var corePrimitives = require('./primitives.js');
 
- var corePsParser = require('./ps_parser.js');
 
- var error = sharedUtil.error;
 
- var info = sharedUtil.info;
 
- var isArray = sharedUtil.isArray;
 
- var isBool = sharedUtil.isBool;
 
- var isDict = corePrimitives.isDict;
 
- var isStream = corePrimitives.isStream;
 
- var PostScriptLexer = corePsParser.PostScriptLexer;
 
- var PostScriptParser = corePsParser.PostScriptParser;
 
- var PDFFunction = function PDFFunctionClosure() {
 
-   var CONSTRUCT_SAMPLED = 0;
 
-   var CONSTRUCT_INTERPOLATED = 2;
 
-   var CONSTRUCT_STICHED = 3;
 
-   var CONSTRUCT_POSTSCRIPT = 4;
 
-   return {
 
-     getSampleArray: function PDFFunction_getSampleArray(size, outputSize, bps, str) {
 
-       var i, ii;
 
-       var length = 1;
 
-       for (i = 0, ii = size.length; i < ii; i++) {
 
-         length *= size[i];
 
-       }
 
-       length *= outputSize;
 
-       var array = new Array(length);
 
-       var codeSize = 0;
 
-       var codeBuf = 0;
 
-       var sampleMul = 1.0 / (Math.pow(2.0, bps) - 1);
 
-       var strBytes = str.getBytes((length * bps + 7) / 8);
 
-       var strIdx = 0;
 
-       for (i = 0; i < length; i++) {
 
-         while (codeSize < bps) {
 
-           codeBuf <<= 8;
 
-           codeBuf |= strBytes[strIdx++];
 
-           codeSize += 8;
 
-         }
 
-         codeSize -= bps;
 
-         array[i] = (codeBuf >> codeSize) * sampleMul;
 
-         codeBuf &= (1 << codeSize) - 1;
 
-       }
 
-       return array;
 
-     },
 
-     getIR: function PDFFunction_getIR(xref, fn) {
 
-       var dict = fn.dict;
 
-       if (!dict) {
 
-         dict = fn;
 
-       }
 
-       var types = [this.constructSampled, null, this.constructInterpolated, this.constructStiched, this.constructPostScript];
 
-       var typeNum = dict.get('FunctionType');
 
-       var typeFn = types[typeNum];
 
-       if (!typeFn) {
 
-         error('Unknown type of function');
 
-       }
 
-       return typeFn.call(this, fn, dict, xref);
 
-     },
 
-     fromIR: function PDFFunction_fromIR(IR) {
 
-       var type = IR[0];
 
-       switch (type) {
 
-         case CONSTRUCT_SAMPLED:
 
-           return this.constructSampledFromIR(IR);
 
-         case CONSTRUCT_INTERPOLATED:
 
-           return this.constructInterpolatedFromIR(IR);
 
-         case CONSTRUCT_STICHED:
 
-           return this.constructStichedFromIR(IR);
 
-         default:
 
-           return this.constructPostScriptFromIR(IR);
 
-       }
 
-     },
 
-     parse: function PDFFunction_parse(xref, fn) {
 
-       var IR = this.getIR(xref, fn);
 
-       return this.fromIR(IR);
 
-     },
 
-     parseArray: function PDFFunction_parseArray(xref, fnObj) {
 
-       if (!isArray(fnObj)) {
 
-         return this.parse(xref, fnObj);
 
-       }
 
-       var fnArray = [];
 
-       for (var j = 0, jj = fnObj.length; j < jj; j++) {
 
-         var obj = xref.fetchIfRef(fnObj[j]);
 
-         fnArray.push(PDFFunction.parse(xref, obj));
 
-       }
 
-       return function (src, srcOffset, dest, destOffset) {
 
-         for (var i = 0, ii = fnArray.length; i < ii; i++) {
 
-           fnArray[i](src, srcOffset, dest, destOffset + i);
 
-         }
 
-       };
 
-     },
 
-     constructSampled: function PDFFunction_constructSampled(str, dict) {
 
-       function toMultiArray(arr) {
 
-         var inputLength = arr.length;
 
-         var out = [];
 
-         var index = 0;
 
-         for (var i = 0; i < inputLength; i += 2) {
 
-           out[index] = [arr[i], arr[i + 1]];
 
-           ++index;
 
-         }
 
-         return out;
 
-       }
 
-       var domain = dict.getArray('Domain');
 
-       var range = dict.getArray('Range');
 
-       if (!domain || !range) {
 
-         error('No domain or range');
 
-       }
 
-       var inputSize = domain.length / 2;
 
-       var outputSize = range.length / 2;
 
-       domain = toMultiArray(domain);
 
-       range = toMultiArray(range);
 
-       var size = dict.get('Size');
 
-       var bps = dict.get('BitsPerSample');
 
-       var order = dict.get('Order') || 1;
 
-       if (order !== 1) {
 
-         info('No support for cubic spline interpolation: ' + order);
 
-       }
 
-       var encode = dict.getArray('Encode');
 
-       if (!encode) {
 
-         encode = [];
 
-         for (var i = 0; i < inputSize; ++i) {
 
-           encode.push(0);
 
-           encode.push(size[i] - 1);
 
-         }
 
-       }
 
-       encode = toMultiArray(encode);
 
-       var decode = dict.getArray('Decode');
 
-       if (!decode) {
 
-         decode = range;
 
-       } else {
 
-         decode = toMultiArray(decode);
 
-       }
 
-       var samples = this.getSampleArray(size, outputSize, bps, str);
 
-       return [CONSTRUCT_SAMPLED, inputSize, domain, encode, decode, samples, size, outputSize, Math.pow(2, bps) - 1, range];
 
-     },
 
-     constructSampledFromIR: function PDFFunction_constructSampledFromIR(IR) {
 
-       function interpolate(x, xmin, xmax, ymin, ymax) {
 
-         return ymin + (x - xmin) * ((ymax - ymin) / (xmax - xmin));
 
-       }
 
-       return function constructSampledFromIRResult(src, srcOffset, dest, destOffset) {
 
-         var m = IR[1];
 
-         var domain = IR[2];
 
-         var encode = IR[3];
 
-         var decode = IR[4];
 
-         var samples = IR[5];
 
-         var size = IR[6];
 
-         var n = IR[7];
 
-         var range = IR[9];
 
-         var cubeVertices = 1 << m;
 
-         var cubeN = new Float64Array(cubeVertices);
 
-         var cubeVertex = new Uint32Array(cubeVertices);
 
-         var i, j;
 
-         for (j = 0; j < cubeVertices; j++) {
 
-           cubeN[j] = 1;
 
-         }
 
-         var k = n,
 
-             pos = 1;
 
-         for (i = 0; i < m; ++i) {
 
-           var domain_2i = domain[i][0];
 
-           var domain_2i_1 = domain[i][1];
 
-           var xi = Math.min(Math.max(src[srcOffset + i], domain_2i), domain_2i_1);
 
-           var e = interpolate(xi, domain_2i, domain_2i_1, encode[i][0], encode[i][1]);
 
-           var size_i = size[i];
 
-           e = Math.min(Math.max(e, 0), size_i - 1);
 
-           var e0 = e < size_i - 1 ? Math.floor(e) : e - 1;
 
-           var n0 = e0 + 1 - e;
 
-           var n1 = e - e0;
 
-           var offset0 = e0 * k;
 
-           var offset1 = offset0 + k;
 
-           for (j = 0; j < cubeVertices; j++) {
 
-             if (j & pos) {
 
-               cubeN[j] *= n1;
 
-               cubeVertex[j] += offset1;
 
-             } else {
 
-               cubeN[j] *= n0;
 
-               cubeVertex[j] += offset0;
 
-             }
 
-           }
 
-           k *= size_i;
 
-           pos <<= 1;
 
-         }
 
-         for (j = 0; j < n; ++j) {
 
-           var rj = 0;
 
-           for (i = 0; i < cubeVertices; i++) {
 
-             rj += samples[cubeVertex[i] + j] * cubeN[i];
 
-           }
 
-           rj = interpolate(rj, 0, 1, decode[j][0], decode[j][1]);
 
-           dest[destOffset + j] = Math.min(Math.max(rj, range[j][0]), range[j][1]);
 
-         }
 
-       };
 
-     },
 
-     constructInterpolated: function PDFFunction_constructInterpolated(str, dict) {
 
-       var c0 = dict.getArray('C0') || [0];
 
-       var c1 = dict.getArray('C1') || [1];
 
-       var n = dict.get('N');
 
-       if (!isArray(c0) || !isArray(c1)) {
 
-         error('Illegal dictionary for interpolated function');
 
-       }
 
-       var length = c0.length;
 
-       var diff = [];
 
-       for (var i = 0; i < length; ++i) {
 
-         diff.push(c1[i] - c0[i]);
 
-       }
 
-       return [CONSTRUCT_INTERPOLATED, c0, diff, n];
 
-     },
 
-     constructInterpolatedFromIR: function PDFFunction_constructInterpolatedFromIR(IR) {
 
-       var c0 = IR[1];
 
-       var diff = IR[2];
 
-       var n = IR[3];
 
-       var length = diff.length;
 
-       return function constructInterpolatedFromIRResult(src, srcOffset, dest, destOffset) {
 
-         var x = n === 1 ? src[srcOffset] : Math.pow(src[srcOffset], n);
 
-         for (var j = 0; j < length; ++j) {
 
-           dest[destOffset + j] = c0[j] + x * diff[j];
 
-         }
 
-       };
 
-     },
 
-     constructStiched: function PDFFunction_constructStiched(fn, dict, xref) {
 
-       var domain = dict.getArray('Domain');
 
-       if (!domain) {
 
-         error('No domain');
 
-       }
 
-       var inputSize = domain.length / 2;
 
-       if (inputSize !== 1) {
 
-         error('Bad domain for stiched function');
 
-       }
 
-       var fnRefs = dict.get('Functions');
 
-       var fns = [];
 
-       for (var i = 0, ii = fnRefs.length; i < ii; ++i) {
 
-         fns.push(PDFFunction.getIR(xref, xref.fetchIfRef(fnRefs[i])));
 
-       }
 
-       var bounds = dict.getArray('Bounds');
 
-       var encode = dict.getArray('Encode');
 
-       return [CONSTRUCT_STICHED, domain, bounds, encode, fns];
 
-     },
 
-     constructStichedFromIR: function PDFFunction_constructStichedFromIR(IR) {
 
-       var domain = IR[1];
 
-       var bounds = IR[2];
 
-       var encode = IR[3];
 
-       var fnsIR = IR[4];
 
-       var fns = [];
 
-       var tmpBuf = new Float32Array(1);
 
-       for (var i = 0, ii = fnsIR.length; i < ii; i++) {
 
-         fns.push(PDFFunction.fromIR(fnsIR[i]));
 
-       }
 
-       return function constructStichedFromIRResult(src, srcOffset, dest, destOffset) {
 
-         var clip = function constructStichedFromIRClip(v, min, max) {
 
-           if (v > max) {
 
-             v = max;
 
-           } else if (v < min) {
 
-             v = min;
 
-           }
 
-           return v;
 
-         };
 
-         var v = clip(src[srcOffset], domain[0], domain[1]);
 
-         for (var i = 0, ii = bounds.length; i < ii; ++i) {
 
-           if (v < bounds[i]) {
 
-             break;
 
-           }
 
-         }
 
-         var dmin = domain[0];
 
-         if (i > 0) {
 
-           dmin = bounds[i - 1];
 
-         }
 
-         var dmax = domain[1];
 
-         if (i < bounds.length) {
 
-           dmax = bounds[i];
 
-         }
 
-         var rmin = encode[2 * i];
 
-         var rmax = encode[2 * i + 1];
 
-         tmpBuf[0] = dmin === dmax ? rmin : rmin + (v - dmin) * (rmax - rmin) / (dmax - dmin);
 
-         fns[i](tmpBuf, 0, dest, destOffset);
 
-       };
 
-     },
 
-     constructPostScript: function PDFFunction_constructPostScript(fn, dict, xref) {
 
-       var domain = dict.getArray('Domain');
 
-       var range = dict.getArray('Range');
 
-       if (!domain) {
 
-         error('No domain.');
 
-       }
 
-       if (!range) {
 
-         error('No range.');
 
-       }
 
-       var lexer = new PostScriptLexer(fn);
 
-       var parser = new PostScriptParser(lexer);
 
-       var code = parser.parse();
 
-       return [CONSTRUCT_POSTSCRIPT, domain, range, code];
 
-     },
 
-     constructPostScriptFromIR: function PDFFunction_constructPostScriptFromIR(IR) {
 
-       var domain = IR[1];
 
-       var range = IR[2];
 
-       var code = IR[3];
 
-       var compiled = new PostScriptCompiler().compile(code, domain, range);
 
-       if (compiled) {
 
-         return new Function('src', 'srcOffset', 'dest', 'destOffset', compiled);
 
-       }
 
-       info('Unable to compile PS function');
 
-       var numOutputs = range.length >> 1;
 
-       var numInputs = domain.length >> 1;
 
-       var evaluator = new PostScriptEvaluator(code);
 
-       var cache = Object.create(null);
 
-       var MAX_CACHE_SIZE = 2048 * 4;
 
-       var cache_available = MAX_CACHE_SIZE;
 
-       var tmpBuf = new Float32Array(numInputs);
 
-       return function constructPostScriptFromIRResult(src, srcOffset, dest, destOffset) {
 
-         var i, value;
 
-         var key = '';
 
-         var input = tmpBuf;
 
-         for (i = 0; i < numInputs; i++) {
 
-           value = src[srcOffset + i];
 
-           input[i] = value;
 
-           key += value + '_';
 
-         }
 
-         var cachedValue = cache[key];
 
-         if (cachedValue !== undefined) {
 
-           dest.set(cachedValue, destOffset);
 
-           return;
 
-         }
 
-         var output = new Float32Array(numOutputs);
 
-         var stack = evaluator.execute(input);
 
-         var stackIndex = stack.length - numOutputs;
 
-         for (i = 0; i < numOutputs; i++) {
 
-           value = stack[stackIndex + i];
 
-           var bound = range[i * 2];
 
-           if (value < bound) {
 
-             value = bound;
 
-           } else {
 
-             bound = range[i * 2 + 1];
 
-             if (value > bound) {
 
-               value = bound;
 
-             }
 
-           }
 
-           output[i] = value;
 
-         }
 
-         if (cache_available > 0) {
 
-           cache_available--;
 
-           cache[key] = output;
 
-         }
 
-         dest.set(output, destOffset);
 
-       };
 
-     }
 
-   };
 
- }();
 
- function isPDFFunction(v) {
 
-   var fnDict;
 
-   if (typeof v !== 'object') {
 
-     return false;
 
-   } else if (isDict(v)) {
 
-     fnDict = v;
 
-   } else if (isStream(v)) {
 
-     fnDict = v.dict;
 
-   } else {
 
-     return false;
 
-   }
 
-   return fnDict.has('FunctionType');
 
- }
 
- var PostScriptStack = function PostScriptStackClosure() {
 
-   var MAX_STACK_SIZE = 100;
 
-   function PostScriptStack(initialStack) {
 
-     this.stack = !initialStack ? [] : Array.prototype.slice.call(initialStack, 0);
 
-   }
 
-   PostScriptStack.prototype = {
 
-     push: function PostScriptStack_push(value) {
 
-       if (this.stack.length >= MAX_STACK_SIZE) {
 
-         error('PostScript function stack overflow.');
 
-       }
 
-       this.stack.push(value);
 
-     },
 
-     pop: function PostScriptStack_pop() {
 
-       if (this.stack.length <= 0) {
 
-         error('PostScript function stack underflow.');
 
-       }
 
-       return this.stack.pop();
 
-     },
 
-     copy: function PostScriptStack_copy(n) {
 
-       if (this.stack.length + n >= MAX_STACK_SIZE) {
 
-         error('PostScript function stack overflow.');
 
-       }
 
-       var stack = this.stack;
 
-       for (var i = stack.length - n, j = n - 1; j >= 0; j--, i++) {
 
-         stack.push(stack[i]);
 
-       }
 
-     },
 
-     index: function PostScriptStack_index(n) {
 
-       this.push(this.stack[this.stack.length - n - 1]);
 
-     },
 
-     roll: function PostScriptStack_roll(n, p) {
 
-       var stack = this.stack;
 
-       var l = stack.length - n;
 
-       var r = stack.length - 1,
 
-           c = l + (p - Math.floor(p / n) * n),
 
-           i,
 
-           j,
 
-           t;
 
-       for (i = l, j = r; i < j; i++, j--) {
 
-         t = stack[i];
 
-         stack[i] = stack[j];
 
-         stack[j] = t;
 
-       }
 
-       for (i = l, j = c - 1; i < j; i++, j--) {
 
-         t = stack[i];
 
-         stack[i] = stack[j];
 
-         stack[j] = t;
 
-       }
 
-       for (i = c, j = r; i < j; i++, j--) {
 
-         t = stack[i];
 
-         stack[i] = stack[j];
 
-         stack[j] = t;
 
-       }
 
-     }
 
-   };
 
-   return PostScriptStack;
 
- }();
 
- var PostScriptEvaluator = function PostScriptEvaluatorClosure() {
 
-   function PostScriptEvaluator(operators) {
 
-     this.operators = operators;
 
-   }
 
-   PostScriptEvaluator.prototype = {
 
-     execute: function PostScriptEvaluator_execute(initialStack) {
 
-       var stack = new PostScriptStack(initialStack);
 
-       var counter = 0;
 
-       var operators = this.operators;
 
-       var length = operators.length;
 
-       var operator, a, b;
 
-       while (counter < length) {
 
-         operator = operators[counter++];
 
-         if (typeof operator === 'number') {
 
-           stack.push(operator);
 
-           continue;
 
-         }
 
-         switch (operator) {
 
-           case 'jz':
 
-             b = stack.pop();
 
-             a = stack.pop();
 
-             if (!a) {
 
-               counter = b;
 
-             }
 
-             break;
 
-           case 'j':
 
-             a = stack.pop();
 
-             counter = a;
 
-             break;
 
-           case 'abs':
 
-             a = stack.pop();
 
-             stack.push(Math.abs(a));
 
-             break;
 
-           case 'add':
 
-             b = stack.pop();
 
-             a = stack.pop();
 
-             stack.push(a + b);
 
-             break;
 
-           case 'and':
 
-             b = stack.pop();
 
-             a = stack.pop();
 
-             if (isBool(a) && isBool(b)) {
 
-               stack.push(a && b);
 
-             } else {
 
-               stack.push(a & b);
 
-             }
 
-             break;
 
-           case 'atan':
 
-             a = stack.pop();
 
-             stack.push(Math.atan(a));
 
-             break;
 
-           case 'bitshift':
 
-             b = stack.pop();
 
-             a = stack.pop();
 
-             if (a > 0) {
 
-               stack.push(a << b);
 
-             } else {
 
-               stack.push(a >> b);
 
-             }
 
-             break;
 
-           case 'ceiling':
 
-             a = stack.pop();
 
-             stack.push(Math.ceil(a));
 
-             break;
 
-           case 'copy':
 
-             a = stack.pop();
 
-             stack.copy(a);
 
-             break;
 
-           case 'cos':
 
-             a = stack.pop();
 
-             stack.push(Math.cos(a));
 
-             break;
 
-           case 'cvi':
 
-             a = stack.pop() | 0;
 
-             stack.push(a);
 
-             break;
 
-           case 'cvr':
 
-             break;
 
-           case 'div':
 
-             b = stack.pop();
 
-             a = stack.pop();
 
-             stack.push(a / b);
 
-             break;
 
-           case 'dup':
 
-             stack.copy(1);
 
-             break;
 
-           case 'eq':
 
-             b = stack.pop();
 
-             a = stack.pop();
 
-             stack.push(a === b);
 
-             break;
 
-           case 'exch':
 
-             stack.roll(2, 1);
 
-             break;
 
-           case 'exp':
 
-             b = stack.pop();
 
-             a = stack.pop();
 
-             stack.push(Math.pow(a, b));
 
-             break;
 
-           case 'false':
 
-             stack.push(false);
 
-             break;
 
-           case 'floor':
 
-             a = stack.pop();
 
-             stack.push(Math.floor(a));
 
-             break;
 
-           case 'ge':
 
-             b = stack.pop();
 
-             a = stack.pop();
 
-             stack.push(a >= b);
 
-             break;
 
-           case 'gt':
 
-             b = stack.pop();
 
-             a = stack.pop();
 
-             stack.push(a > b);
 
-             break;
 
-           case 'idiv':
 
-             b = stack.pop();
 
-             a = stack.pop();
 
-             stack.push(a / b | 0);
 
-             break;
 
-           case 'index':
 
-             a = stack.pop();
 
-             stack.index(a);
 
-             break;
 
-           case 'le':
 
-             b = stack.pop();
 
-             a = stack.pop();
 
-             stack.push(a <= b);
 
-             break;
 
-           case 'ln':
 
-             a = stack.pop();
 
-             stack.push(Math.log(a));
 
-             break;
 
-           case 'log':
 
-             a = stack.pop();
 
-             stack.push(Math.log(a) / Math.LN10);
 
-             break;
 
-           case 'lt':
 
-             b = stack.pop();
 
-             a = stack.pop();
 
-             stack.push(a < b);
 
-             break;
 
-           case 'mod':
 
-             b = stack.pop();
 
-             a = stack.pop();
 
-             stack.push(a % b);
 
-             break;
 
-           case 'mul':
 
-             b = stack.pop();
 
-             a = stack.pop();
 
-             stack.push(a * b);
 
-             break;
 
-           case 'ne':
 
-             b = stack.pop();
 
-             a = stack.pop();
 
-             stack.push(a !== b);
 
-             break;
 
-           case 'neg':
 
-             a = stack.pop();
 
-             stack.push(-a);
 
-             break;
 
-           case 'not':
 
-             a = stack.pop();
 
-             if (isBool(a)) {
 
-               stack.push(!a);
 
-             } else {
 
-               stack.push(~a);
 
-             }
 
-             break;
 
-           case 'or':
 
-             b = stack.pop();
 
-             a = stack.pop();
 
-             if (isBool(a) && isBool(b)) {
 
-               stack.push(a || b);
 
-             } else {
 
-               stack.push(a | b);
 
-             }
 
-             break;
 
-           case 'pop':
 
-             stack.pop();
 
-             break;
 
-           case 'roll':
 
-             b = stack.pop();
 
-             a = stack.pop();
 
-             stack.roll(a, b);
 
-             break;
 
-           case 'round':
 
-             a = stack.pop();
 
-             stack.push(Math.round(a));
 
-             break;
 
-           case 'sin':
 
-             a = stack.pop();
 
-             stack.push(Math.sin(a));
 
-             break;
 
-           case 'sqrt':
 
-             a = stack.pop();
 
-             stack.push(Math.sqrt(a));
 
-             break;
 
-           case 'sub':
 
-             b = stack.pop();
 
-             a = stack.pop();
 
-             stack.push(a - b);
 
-             break;
 
-           case 'true':
 
-             stack.push(true);
 
-             break;
 
-           case 'truncate':
 
-             a = stack.pop();
 
-             a = a < 0 ? Math.ceil(a) : Math.floor(a);
 
-             stack.push(a);
 
-             break;
 
-           case 'xor':
 
-             b = stack.pop();
 
-             a = stack.pop();
 
-             if (isBool(a) && isBool(b)) {
 
-               stack.push(a !== b);
 
-             } else {
 
-               stack.push(a ^ b);
 
-             }
 
-             break;
 
-           default:
 
-             error('Unknown operator ' + operator);
 
-             break;
 
-         }
 
-       }
 
-       return stack.stack;
 
-     }
 
-   };
 
-   return PostScriptEvaluator;
 
- }();
 
- var PostScriptCompiler = function PostScriptCompilerClosure() {
 
-   function AstNode(type) {
 
-     this.type = type;
 
-   }
 
-   AstNode.prototype.visit = function (visitor) {
 
-     throw new Error('abstract method');
 
-   };
 
-   function AstArgument(index, min, max) {
 
-     AstNode.call(this, 'args');
 
-     this.index = index;
 
-     this.min = min;
 
-     this.max = max;
 
-   }
 
-   AstArgument.prototype = Object.create(AstNode.prototype);
 
-   AstArgument.prototype.visit = function (visitor) {
 
-     visitor.visitArgument(this);
 
-   };
 
-   function AstLiteral(number) {
 
-     AstNode.call(this, 'literal');
 
-     this.number = number;
 
-     this.min = number;
 
-     this.max = number;
 
-   }
 
-   AstLiteral.prototype = Object.create(AstNode.prototype);
 
-   AstLiteral.prototype.visit = function (visitor) {
 
-     visitor.visitLiteral(this);
 
-   };
 
-   function AstBinaryOperation(op, arg1, arg2, min, max) {
 
-     AstNode.call(this, 'binary');
 
-     this.op = op;
 
-     this.arg1 = arg1;
 
-     this.arg2 = arg2;
 
-     this.min = min;
 
-     this.max = max;
 
-   }
 
-   AstBinaryOperation.prototype = Object.create(AstNode.prototype);
 
-   AstBinaryOperation.prototype.visit = function (visitor) {
 
-     visitor.visitBinaryOperation(this);
 
-   };
 
-   function AstMin(arg, max) {
 
-     AstNode.call(this, 'max');
 
-     this.arg = arg;
 
-     this.min = arg.min;
 
-     this.max = max;
 
-   }
 
-   AstMin.prototype = Object.create(AstNode.prototype);
 
-   AstMin.prototype.visit = function (visitor) {
 
-     visitor.visitMin(this);
 
-   };
 
-   function AstVariable(index, min, max) {
 
-     AstNode.call(this, 'var');
 
-     this.index = index;
 
-     this.min = min;
 
-     this.max = max;
 
-   }
 
-   AstVariable.prototype = Object.create(AstNode.prototype);
 
-   AstVariable.prototype.visit = function (visitor) {
 
-     visitor.visitVariable(this);
 
-   };
 
-   function AstVariableDefinition(variable, arg) {
 
-     AstNode.call(this, 'definition');
 
-     this.variable = variable;
 
-     this.arg = arg;
 
-   }
 
-   AstVariableDefinition.prototype = Object.create(AstNode.prototype);
 
-   AstVariableDefinition.prototype.visit = function (visitor) {
 
-     visitor.visitVariableDefinition(this);
 
-   };
 
-   function ExpressionBuilderVisitor() {
 
-     this.parts = [];
 
-   }
 
-   ExpressionBuilderVisitor.prototype = {
 
-     visitArgument: function (arg) {
 
-       this.parts.push('Math.max(', arg.min, ', Math.min(', arg.max, ', src[srcOffset + ', arg.index, ']))');
 
-     },
 
-     visitVariable: function (variable) {
 
-       this.parts.push('v', variable.index);
 
-     },
 
-     visitLiteral: function (literal) {
 
-       this.parts.push(literal.number);
 
-     },
 
-     visitBinaryOperation: function (operation) {
 
-       this.parts.push('(');
 
-       operation.arg1.visit(this);
 
-       this.parts.push(' ', operation.op, ' ');
 
-       operation.arg2.visit(this);
 
-       this.parts.push(')');
 
-     },
 
-     visitVariableDefinition: function (definition) {
 
-       this.parts.push('var ');
 
-       definition.variable.visit(this);
 
-       this.parts.push(' = ');
 
-       definition.arg.visit(this);
 
-       this.parts.push(';');
 
-     },
 
-     visitMin: function (max) {
 
-       this.parts.push('Math.min(');
 
-       max.arg.visit(this);
 
-       this.parts.push(', ', max.max, ')');
 
-     },
 
-     toString: function () {
 
-       return this.parts.join('');
 
-     }
 
-   };
 
-   function buildAddOperation(num1, num2) {
 
-     if (num2.type === 'literal' && num2.number === 0) {
 
-       return num1;
 
-     }
 
-     if (num1.type === 'literal' && num1.number === 0) {
 
-       return num2;
 
-     }
 
-     if (num2.type === 'literal' && num1.type === 'literal') {
 
-       return new AstLiteral(num1.number + num2.number);
 
-     }
 
-     return new AstBinaryOperation('+', num1, num2, num1.min + num2.min, num1.max + num2.max);
 
-   }
 
-   function buildMulOperation(num1, num2) {
 
-     if (num2.type === 'literal') {
 
-       if (num2.number === 0) {
 
-         return new AstLiteral(0);
 
-       } else if (num2.number === 1) {
 
-         return num1;
 
-       } else if (num1.type === 'literal') {
 
-         return new AstLiteral(num1.number * num2.number);
 
-       }
 
-     }
 
-     if (num1.type === 'literal') {
 
-       if (num1.number === 0) {
 
-         return new AstLiteral(0);
 
-       } else if (num1.number === 1) {
 
-         return num2;
 
-       }
 
-     }
 
-     var min = Math.min(num1.min * num2.min, num1.min * num2.max, num1.max * num2.min, num1.max * num2.max);
 
-     var max = Math.max(num1.min * num2.min, num1.min * num2.max, num1.max * num2.min, num1.max * num2.max);
 
-     return new AstBinaryOperation('*', num1, num2, min, max);
 
-   }
 
-   function buildSubOperation(num1, num2) {
 
-     if (num2.type === 'literal') {
 
-       if (num2.number === 0) {
 
-         return num1;
 
-       } else if (num1.type === 'literal') {
 
-         return new AstLiteral(num1.number - num2.number);
 
-       }
 
-     }
 
-     if (num2.type === 'binary' && num2.op === '-' && num1.type === 'literal' && num1.number === 1 && num2.arg1.type === 'literal' && num2.arg1.number === 1) {
 
-       return num2.arg2;
 
-     }
 
-     return new AstBinaryOperation('-', num1, num2, num1.min - num2.max, num1.max - num2.min);
 
-   }
 
-   function buildMinOperation(num1, max) {
 
-     if (num1.min >= max) {
 
-       return new AstLiteral(max);
 
-     } else if (num1.max <= max) {
 
-       return num1;
 
-     }
 
-     return new AstMin(num1, max);
 
-   }
 
-   function PostScriptCompiler() {}
 
-   PostScriptCompiler.prototype = {
 
-     compile: function PostScriptCompiler_compile(code, domain, range) {
 
-       var stack = [];
 
-       var i, ii;
 
-       var instructions = [];
 
-       var inputSize = domain.length >> 1,
 
-           outputSize = range.length >> 1;
 
-       var lastRegister = 0;
 
-       var n, j;
 
-       var num1, num2, ast1, ast2, tmpVar, item;
 
-       for (i = 0; i < inputSize; i++) {
 
-         stack.push(new AstArgument(i, domain[i * 2], domain[i * 2 + 1]));
 
-       }
 
-       for (i = 0, ii = code.length; i < ii; i++) {
 
-         item = code[i];
 
-         if (typeof item === 'number') {
 
-           stack.push(new AstLiteral(item));
 
-           continue;
 
-         }
 
-         switch (item) {
 
-           case 'add':
 
-             if (stack.length < 2) {
 
-               return null;
 
-             }
 
-             num2 = stack.pop();
 
-             num1 = stack.pop();
 
-             stack.push(buildAddOperation(num1, num2));
 
-             break;
 
-           case 'cvr':
 
-             if (stack.length < 1) {
 
-               return null;
 
-             }
 
-             break;
 
-           case 'mul':
 
-             if (stack.length < 2) {
 
-               return null;
 
-             }
 
-             num2 = stack.pop();
 
-             num1 = stack.pop();
 
-             stack.push(buildMulOperation(num1, num2));
 
-             break;
 
-           case 'sub':
 
-             if (stack.length < 2) {
 
-               return null;
 
-             }
 
-             num2 = stack.pop();
 
-             num1 = stack.pop();
 
-             stack.push(buildSubOperation(num1, num2));
 
-             break;
 
-           case 'exch':
 
-             if (stack.length < 2) {
 
-               return null;
 
-             }
 
-             ast1 = stack.pop();
 
-             ast2 = stack.pop();
 
-             stack.push(ast1, ast2);
 
-             break;
 
-           case 'pop':
 
-             if (stack.length < 1) {
 
-               return null;
 
-             }
 
-             stack.pop();
 
-             break;
 
-           case 'index':
 
-             if (stack.length < 1) {
 
-               return null;
 
-             }
 
-             num1 = stack.pop();
 
-             if (num1.type !== 'literal') {
 
-               return null;
 
-             }
 
-             n = num1.number;
 
-             if (n < 0 || (n | 0) !== n || stack.length < n) {
 
-               return null;
 
-             }
 
-             ast1 = stack[stack.length - n - 1];
 
-             if (ast1.type === 'literal' || ast1.type === 'var') {
 
-               stack.push(ast1);
 
-               break;
 
-             }
 
-             tmpVar = new AstVariable(lastRegister++, ast1.min, ast1.max);
 
-             stack[stack.length - n - 1] = tmpVar;
 
-             stack.push(tmpVar);
 
-             instructions.push(new AstVariableDefinition(tmpVar, ast1));
 
-             break;
 
-           case 'dup':
 
-             if (stack.length < 1) {
 
-               return null;
 
-             }
 
-             if (typeof code[i + 1] === 'number' && code[i + 2] === 'gt' && code[i + 3] === i + 7 && code[i + 4] === 'jz' && code[i + 5] === 'pop' && code[i + 6] === code[i + 1]) {
 
-               num1 = stack.pop();
 
-               stack.push(buildMinOperation(num1, code[i + 1]));
 
-               i += 6;
 
-               break;
 
-             }
 
-             ast1 = stack[stack.length - 1];
 
-             if (ast1.type === 'literal' || ast1.type === 'var') {
 
-               stack.push(ast1);
 
-               break;
 
-             }
 
-             tmpVar = new AstVariable(lastRegister++, ast1.min, ast1.max);
 
-             stack[stack.length - 1] = tmpVar;
 
-             stack.push(tmpVar);
 
-             instructions.push(new AstVariableDefinition(tmpVar, ast1));
 
-             break;
 
-           case 'roll':
 
-             if (stack.length < 2) {
 
-               return null;
 
-             }
 
-             num2 = stack.pop();
 
-             num1 = stack.pop();
 
-             if (num2.type !== 'literal' || num1.type !== 'literal') {
 
-               return null;
 
-             }
 
-             j = num2.number;
 
-             n = num1.number;
 
-             if (n <= 0 || (n | 0) !== n || (j | 0) !== j || stack.length < n) {
 
-               return null;
 
-             }
 
-             j = (j % n + n) % n;
 
-             if (j === 0) {
 
-               break;
 
-             }
 
-             Array.prototype.push.apply(stack, stack.splice(stack.length - n, n - j));
 
-             break;
 
-           default:
 
-             return null;
 
-         }
 
-       }
 
-       if (stack.length !== outputSize) {
 
-         return null;
 
-       }
 
-       var result = [];
 
-       instructions.forEach(function (instruction) {
 
-         var statementBuilder = new ExpressionBuilderVisitor();
 
-         instruction.visit(statementBuilder);
 
-         result.push(statementBuilder.toString());
 
-       });
 
-       stack.forEach(function (expr, i) {
 
-         var statementBuilder = new ExpressionBuilderVisitor();
 
-         expr.visit(statementBuilder);
 
-         var min = range[i * 2],
 
-             max = range[i * 2 + 1];
 
-         var out = [statementBuilder.toString()];
 
-         if (min > expr.min) {
 
-           out.unshift('Math.max(', min, ', ');
 
-           out.push(')');
 
-         }
 
-         if (max < expr.max) {
 
-           out.unshift('Math.min(', max, ', ');
 
-           out.push(')');
 
-         }
 
-         out.unshift('dest[destOffset + ', i, '] = ');
 
-         out.push(';');
 
-         result.push(out.join(''));
 
-       });
 
-       return result.join('\n');
 
-     }
 
-   };
 
-   return PostScriptCompiler;
 
- }();
 
- exports.isPDFFunction = isPDFFunction;
 
- exports.PDFFunction = PDFFunction;
 
- exports.PostScriptEvaluator = PostScriptEvaluator;
 
- exports.PostScriptCompiler = PostScriptCompiler;
 
 
  |