function.js 35 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142
  1. /* Copyright 2017 Mozilla Foundation
  2. *
  3. * Licensed under the Apache License, Version 2.0 (the "License");
  4. * you may not use this file except in compliance with the License.
  5. * You may obtain a copy of the License at
  6. *
  7. * http://www.apache.org/licenses/LICENSE-2.0
  8. *
  9. * Unless required by applicable law or agreed to in writing, software
  10. * distributed under the License is distributed on an "AS IS" BASIS,
  11. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. * See the License for the specific language governing permissions and
  13. * limitations under the License.
  14. */
  15. 'use strict';
  16. Object.defineProperty(exports, "__esModule", {
  17. value: true
  18. });
  19. exports.PostScriptCompiler = exports.PostScriptEvaluator = exports.PDFFunctionFactory = exports.isPDFFunction = undefined;
  20. var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
  21. var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
  22. var _util = require('../shared/util');
  23. var _primitives = require('./primitives');
  24. var _ps_parser = require('./ps_parser');
  25. function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  26. var IsEvalSupportedCached = {
  27. get value() {
  28. return (0, _util.shadow)(this, 'value', (0, _util.isEvalSupported)());
  29. }
  30. };
  31. var PDFFunctionFactory = function () {
  32. function PDFFunctionFactory(_ref) {
  33. var xref = _ref.xref,
  34. _ref$isEvalSupported = _ref.isEvalSupported,
  35. isEvalSupported = _ref$isEvalSupported === undefined ? true : _ref$isEvalSupported;
  36. _classCallCheck(this, PDFFunctionFactory);
  37. this.xref = xref;
  38. this.isEvalSupported = isEvalSupported !== false;
  39. }
  40. _createClass(PDFFunctionFactory, [{
  41. key: 'create',
  42. value: function create(fn) {
  43. return PDFFunction.parse({
  44. xref: this.xref,
  45. isEvalSupported: this.isEvalSupported,
  46. fn: fn
  47. });
  48. }
  49. }, {
  50. key: 'createFromArray',
  51. value: function createFromArray(fnObj) {
  52. return PDFFunction.parseArray({
  53. xref: this.xref,
  54. isEvalSupported: this.isEvalSupported,
  55. fnObj: fnObj
  56. });
  57. }
  58. }, {
  59. key: 'createFromIR',
  60. value: function createFromIR(IR) {
  61. return PDFFunction.fromIR({
  62. xref: this.xref,
  63. isEvalSupported: this.isEvalSupported,
  64. IR: IR
  65. });
  66. }
  67. }, {
  68. key: 'createIR',
  69. value: function createIR(fn) {
  70. return PDFFunction.getIR({
  71. xref: this.xref,
  72. isEvalSupported: this.isEvalSupported,
  73. fn: fn
  74. });
  75. }
  76. }]);
  77. return PDFFunctionFactory;
  78. }();
  79. var PDFFunction = function PDFFunctionClosure() {
  80. var CONSTRUCT_SAMPLED = 0;
  81. var CONSTRUCT_INTERPOLATED = 2;
  82. var CONSTRUCT_STICHED = 3;
  83. var CONSTRUCT_POSTSCRIPT = 4;
  84. return {
  85. getSampleArray: function getSampleArray(size, outputSize, bps, stream) {
  86. var i, ii;
  87. var length = 1;
  88. for (i = 0, ii = size.length; i < ii; i++) {
  89. length *= size[i];
  90. }
  91. length *= outputSize;
  92. var array = new Array(length);
  93. var codeSize = 0;
  94. var codeBuf = 0;
  95. var sampleMul = 1.0 / (Math.pow(2.0, bps) - 1);
  96. var strBytes = stream.getBytes((length * bps + 7) / 8);
  97. var strIdx = 0;
  98. for (i = 0; i < length; i++) {
  99. while (codeSize < bps) {
  100. codeBuf <<= 8;
  101. codeBuf |= strBytes[strIdx++];
  102. codeSize += 8;
  103. }
  104. codeSize -= bps;
  105. array[i] = (codeBuf >> codeSize) * sampleMul;
  106. codeBuf &= (1 << codeSize) - 1;
  107. }
  108. return array;
  109. },
  110. getIR: function getIR(_ref2) {
  111. var xref = _ref2.xref,
  112. isEvalSupported = _ref2.isEvalSupported,
  113. fn = _ref2.fn;
  114. var dict = fn.dict;
  115. if (!dict) {
  116. dict = fn;
  117. }
  118. var types = [this.constructSampled, null, this.constructInterpolated, this.constructStiched, this.constructPostScript];
  119. var typeNum = dict.get('FunctionType');
  120. var typeFn = types[typeNum];
  121. if (!typeFn) {
  122. throw new _util.FormatError('Unknown type of function');
  123. }
  124. return typeFn.call(this, {
  125. xref: xref,
  126. isEvalSupported: isEvalSupported,
  127. fn: fn,
  128. dict: dict
  129. });
  130. },
  131. fromIR: function fromIR(_ref3) {
  132. var xref = _ref3.xref,
  133. isEvalSupported = _ref3.isEvalSupported,
  134. IR = _ref3.IR;
  135. var type = IR[0];
  136. switch (type) {
  137. case CONSTRUCT_SAMPLED:
  138. return this.constructSampledFromIR({
  139. xref: xref,
  140. isEvalSupported: isEvalSupported,
  141. IR: IR
  142. });
  143. case CONSTRUCT_INTERPOLATED:
  144. return this.constructInterpolatedFromIR({
  145. xref: xref,
  146. isEvalSupported: isEvalSupported,
  147. IR: IR
  148. });
  149. case CONSTRUCT_STICHED:
  150. return this.constructStichedFromIR({
  151. xref: xref,
  152. isEvalSupported: isEvalSupported,
  153. IR: IR
  154. });
  155. default:
  156. return this.constructPostScriptFromIR({
  157. xref: xref,
  158. isEvalSupported: isEvalSupported,
  159. IR: IR
  160. });
  161. }
  162. },
  163. parse: function parse(_ref4) {
  164. var xref = _ref4.xref,
  165. isEvalSupported = _ref4.isEvalSupported,
  166. fn = _ref4.fn;
  167. var IR = this.getIR({
  168. xref: xref,
  169. isEvalSupported: isEvalSupported,
  170. fn: fn
  171. });
  172. return this.fromIR({
  173. xref: xref,
  174. isEvalSupported: isEvalSupported,
  175. IR: IR
  176. });
  177. },
  178. parseArray: function parseArray(_ref5) {
  179. var xref = _ref5.xref,
  180. isEvalSupported = _ref5.isEvalSupported,
  181. fnObj = _ref5.fnObj;
  182. if (!Array.isArray(fnObj)) {
  183. return this.parse({
  184. xref: xref,
  185. isEvalSupported: isEvalSupported,
  186. fn: fnObj
  187. });
  188. }
  189. var fnArray = [];
  190. for (var j = 0, jj = fnObj.length; j < jj; j++) {
  191. fnArray.push(this.parse({
  192. xref: xref,
  193. isEvalSupported: isEvalSupported,
  194. fn: xref.fetchIfRef(fnObj[j])
  195. }));
  196. }
  197. return function (src, srcOffset, dest, destOffset) {
  198. for (var i = 0, ii = fnArray.length; i < ii; i++) {
  199. fnArray[i](src, srcOffset, dest, destOffset + i);
  200. }
  201. };
  202. },
  203. constructSampled: function constructSampled(_ref6) {
  204. var xref = _ref6.xref,
  205. isEvalSupported = _ref6.isEvalSupported,
  206. fn = _ref6.fn,
  207. dict = _ref6.dict;
  208. function toMultiArray(arr) {
  209. var inputLength = arr.length;
  210. var out = [];
  211. var index = 0;
  212. for (var i = 0; i < inputLength; i += 2) {
  213. out[index] = [arr[i], arr[i + 1]];
  214. ++index;
  215. }
  216. return out;
  217. }
  218. var domain = dict.getArray('Domain');
  219. var range = dict.getArray('Range');
  220. if (!domain || !range) {
  221. throw new _util.FormatError('No domain or range');
  222. }
  223. var inputSize = domain.length / 2;
  224. var outputSize = range.length / 2;
  225. domain = toMultiArray(domain);
  226. range = toMultiArray(range);
  227. var size = dict.get('Size');
  228. var bps = dict.get('BitsPerSample');
  229. var order = dict.get('Order') || 1;
  230. if (order !== 1) {
  231. (0, _util.info)('No support for cubic spline interpolation: ' + order);
  232. }
  233. var encode = dict.getArray('Encode');
  234. if (!encode) {
  235. encode = [];
  236. for (var i = 0; i < inputSize; ++i) {
  237. encode.push(0);
  238. encode.push(size[i] - 1);
  239. }
  240. }
  241. encode = toMultiArray(encode);
  242. var decode = dict.getArray('Decode');
  243. if (!decode) {
  244. decode = range;
  245. } else {
  246. decode = toMultiArray(decode);
  247. }
  248. var samples = this.getSampleArray(size, outputSize, bps, fn);
  249. return [CONSTRUCT_SAMPLED, inputSize, domain, encode, decode, samples, size, outputSize, Math.pow(2, bps) - 1, range];
  250. },
  251. constructSampledFromIR: function constructSampledFromIR(_ref7) {
  252. var xref = _ref7.xref,
  253. isEvalSupported = _ref7.isEvalSupported,
  254. IR = _ref7.IR;
  255. function interpolate(x, xmin, xmax, ymin, ymax) {
  256. return ymin + (x - xmin) * ((ymax - ymin) / (xmax - xmin));
  257. }
  258. return function constructSampledFromIRResult(src, srcOffset, dest, destOffset) {
  259. var m = IR[1];
  260. var domain = IR[2];
  261. var encode = IR[3];
  262. var decode = IR[4];
  263. var samples = IR[5];
  264. var size = IR[6];
  265. var n = IR[7];
  266. var range = IR[9];
  267. var cubeVertices = 1 << m;
  268. var cubeN = new Float64Array(cubeVertices);
  269. var cubeVertex = new Uint32Array(cubeVertices);
  270. var i, j;
  271. for (j = 0; j < cubeVertices; j++) {
  272. cubeN[j] = 1;
  273. }
  274. var k = n,
  275. pos = 1;
  276. for (i = 0; i < m; ++i) {
  277. var domain_2i = domain[i][0];
  278. var domain_2i_1 = domain[i][1];
  279. var xi = Math.min(Math.max(src[srcOffset + i], domain_2i), domain_2i_1);
  280. var e = interpolate(xi, domain_2i, domain_2i_1, encode[i][0], encode[i][1]);
  281. var size_i = size[i];
  282. e = Math.min(Math.max(e, 0), size_i - 1);
  283. var e0 = e < size_i - 1 ? Math.floor(e) : e - 1;
  284. var n0 = e0 + 1 - e;
  285. var n1 = e - e0;
  286. var offset0 = e0 * k;
  287. var offset1 = offset0 + k;
  288. for (j = 0; j < cubeVertices; j++) {
  289. if (j & pos) {
  290. cubeN[j] *= n1;
  291. cubeVertex[j] += offset1;
  292. } else {
  293. cubeN[j] *= n0;
  294. cubeVertex[j] += offset0;
  295. }
  296. }
  297. k *= size_i;
  298. pos <<= 1;
  299. }
  300. for (j = 0; j < n; ++j) {
  301. var rj = 0;
  302. for (i = 0; i < cubeVertices; i++) {
  303. rj += samples[cubeVertex[i] + j] * cubeN[i];
  304. }
  305. rj = interpolate(rj, 0, 1, decode[j][0], decode[j][1]);
  306. dest[destOffset + j] = Math.min(Math.max(rj, range[j][0]), range[j][1]);
  307. }
  308. };
  309. },
  310. constructInterpolated: function constructInterpolated(_ref8) {
  311. var xref = _ref8.xref,
  312. isEvalSupported = _ref8.isEvalSupported,
  313. fn = _ref8.fn,
  314. dict = _ref8.dict;
  315. var c0 = dict.getArray('C0') || [0];
  316. var c1 = dict.getArray('C1') || [1];
  317. var n = dict.get('N');
  318. if (!Array.isArray(c0) || !Array.isArray(c1)) {
  319. throw new _util.FormatError('Illegal dictionary for interpolated function');
  320. }
  321. var length = c0.length;
  322. var diff = [];
  323. for (var i = 0; i < length; ++i) {
  324. diff.push(c1[i] - c0[i]);
  325. }
  326. return [CONSTRUCT_INTERPOLATED, c0, diff, n];
  327. },
  328. constructInterpolatedFromIR: function constructInterpolatedFromIR(_ref9) {
  329. var xref = _ref9.xref,
  330. isEvalSupported = _ref9.isEvalSupported,
  331. IR = _ref9.IR;
  332. var c0 = IR[1];
  333. var diff = IR[2];
  334. var n = IR[3];
  335. var length = diff.length;
  336. return function constructInterpolatedFromIRResult(src, srcOffset, dest, destOffset) {
  337. var x = n === 1 ? src[srcOffset] : Math.pow(src[srcOffset], n);
  338. for (var j = 0; j < length; ++j) {
  339. dest[destOffset + j] = c0[j] + x * diff[j];
  340. }
  341. };
  342. },
  343. constructStiched: function constructStiched(_ref10) {
  344. var xref = _ref10.xref,
  345. isEvalSupported = _ref10.isEvalSupported,
  346. fn = _ref10.fn,
  347. dict = _ref10.dict;
  348. var domain = dict.getArray('Domain');
  349. if (!domain) {
  350. throw new _util.FormatError('No domain');
  351. }
  352. var inputSize = domain.length / 2;
  353. if (inputSize !== 1) {
  354. throw new _util.FormatError('Bad domain for stiched function');
  355. }
  356. var fnRefs = dict.get('Functions');
  357. var fns = [];
  358. for (var i = 0, ii = fnRefs.length; i < ii; ++i) {
  359. fns.push(this.getIR({
  360. xref: xref,
  361. isEvalSupported: isEvalSupported,
  362. fn: xref.fetchIfRef(fnRefs[i])
  363. }));
  364. }
  365. var bounds = dict.getArray('Bounds');
  366. var encode = dict.getArray('Encode');
  367. return [CONSTRUCT_STICHED, domain, bounds, encode, fns];
  368. },
  369. constructStichedFromIR: function constructStichedFromIR(_ref11) {
  370. var xref = _ref11.xref,
  371. isEvalSupported = _ref11.isEvalSupported,
  372. IR = _ref11.IR;
  373. var domain = IR[1];
  374. var bounds = IR[2];
  375. var encode = IR[3];
  376. var fnsIR = IR[4];
  377. var fns = [];
  378. var tmpBuf = new Float32Array(1);
  379. for (var i = 0, ii = fnsIR.length; i < ii; i++) {
  380. fns.push(this.fromIR({
  381. xref: xref,
  382. isEvalSupported: isEvalSupported,
  383. IR: fnsIR[i]
  384. }));
  385. }
  386. return function constructStichedFromIRResult(src, srcOffset, dest, destOffset) {
  387. var clip = function constructStichedFromIRClip(v, min, max) {
  388. if (v > max) {
  389. v = max;
  390. } else if (v < min) {
  391. v = min;
  392. }
  393. return v;
  394. };
  395. var v = clip(src[srcOffset], domain[0], domain[1]);
  396. for (var i = 0, ii = bounds.length; i < ii; ++i) {
  397. if (v < bounds[i]) {
  398. break;
  399. }
  400. }
  401. var dmin = domain[0];
  402. if (i > 0) {
  403. dmin = bounds[i - 1];
  404. }
  405. var dmax = domain[1];
  406. if (i < bounds.length) {
  407. dmax = bounds[i];
  408. }
  409. var rmin = encode[2 * i];
  410. var rmax = encode[2 * i + 1];
  411. tmpBuf[0] = dmin === dmax ? rmin : rmin + (v - dmin) * (rmax - rmin) / (dmax - dmin);
  412. fns[i](tmpBuf, 0, dest, destOffset);
  413. };
  414. },
  415. constructPostScript: function constructPostScript(_ref12) {
  416. var xref = _ref12.xref,
  417. isEvalSupported = _ref12.isEvalSupported,
  418. fn = _ref12.fn,
  419. dict = _ref12.dict;
  420. var domain = dict.getArray('Domain');
  421. var range = dict.getArray('Range');
  422. if (!domain) {
  423. throw new _util.FormatError('No domain.');
  424. }
  425. if (!range) {
  426. throw new _util.FormatError('No range.');
  427. }
  428. var lexer = new _ps_parser.PostScriptLexer(fn);
  429. var parser = new _ps_parser.PostScriptParser(lexer);
  430. var code = parser.parse();
  431. return [CONSTRUCT_POSTSCRIPT, domain, range, code];
  432. },
  433. constructPostScriptFromIR: function constructPostScriptFromIR(_ref13) {
  434. var xref = _ref13.xref,
  435. isEvalSupported = _ref13.isEvalSupported,
  436. IR = _ref13.IR;
  437. var domain = IR[1];
  438. var range = IR[2];
  439. var code = IR[3];
  440. if (isEvalSupported && IsEvalSupportedCached.value) {
  441. var compiled = new PostScriptCompiler().compile(code, domain, range);
  442. if (compiled) {
  443. return new Function('src', 'srcOffset', 'dest', 'destOffset', compiled);
  444. }
  445. }
  446. (0, _util.info)('Unable to compile PS function');
  447. var numOutputs = range.length >> 1;
  448. var numInputs = domain.length >> 1;
  449. var evaluator = new PostScriptEvaluator(code);
  450. var cache = Object.create(null);
  451. var MAX_CACHE_SIZE = 2048 * 4;
  452. var cache_available = MAX_CACHE_SIZE;
  453. var tmpBuf = new Float32Array(numInputs);
  454. return function constructPostScriptFromIRResult(src, srcOffset, dest, destOffset) {
  455. var i, value;
  456. var key = '';
  457. var input = tmpBuf;
  458. for (i = 0; i < numInputs; i++) {
  459. value = src[srcOffset + i];
  460. input[i] = value;
  461. key += value + '_';
  462. }
  463. var cachedValue = cache[key];
  464. if (cachedValue !== undefined) {
  465. dest.set(cachedValue, destOffset);
  466. return;
  467. }
  468. var output = new Float32Array(numOutputs);
  469. var stack = evaluator.execute(input);
  470. var stackIndex = stack.length - numOutputs;
  471. for (i = 0; i < numOutputs; i++) {
  472. value = stack[stackIndex + i];
  473. var bound = range[i * 2];
  474. if (value < bound) {
  475. value = bound;
  476. } else {
  477. bound = range[i * 2 + 1];
  478. if (value > bound) {
  479. value = bound;
  480. }
  481. }
  482. output[i] = value;
  483. }
  484. if (cache_available > 0) {
  485. cache_available--;
  486. cache[key] = output;
  487. }
  488. dest.set(output, destOffset);
  489. };
  490. }
  491. };
  492. }();
  493. function isPDFFunction(v) {
  494. var fnDict;
  495. if ((typeof v === 'undefined' ? 'undefined' : _typeof(v)) !== 'object') {
  496. return false;
  497. } else if ((0, _primitives.isDict)(v)) {
  498. fnDict = v;
  499. } else if ((0, _primitives.isStream)(v)) {
  500. fnDict = v.dict;
  501. } else {
  502. return false;
  503. }
  504. return fnDict.has('FunctionType');
  505. }
  506. var PostScriptStack = function PostScriptStackClosure() {
  507. var MAX_STACK_SIZE = 100;
  508. function PostScriptStack(initialStack) {
  509. this.stack = !initialStack ? [] : Array.prototype.slice.call(initialStack, 0);
  510. }
  511. PostScriptStack.prototype = {
  512. push: function PostScriptStack_push(value) {
  513. if (this.stack.length >= MAX_STACK_SIZE) {
  514. throw new Error('PostScript function stack overflow.');
  515. }
  516. this.stack.push(value);
  517. },
  518. pop: function PostScriptStack_pop() {
  519. if (this.stack.length <= 0) {
  520. throw new Error('PostScript function stack underflow.');
  521. }
  522. return this.stack.pop();
  523. },
  524. copy: function PostScriptStack_copy(n) {
  525. if (this.stack.length + n >= MAX_STACK_SIZE) {
  526. throw new Error('PostScript function stack overflow.');
  527. }
  528. var stack = this.stack;
  529. for (var i = stack.length - n, j = n - 1; j >= 0; j--, i++) {
  530. stack.push(stack[i]);
  531. }
  532. },
  533. index: function PostScriptStack_index(n) {
  534. this.push(this.stack[this.stack.length - n - 1]);
  535. },
  536. roll: function PostScriptStack_roll(n, p) {
  537. var stack = this.stack;
  538. var l = stack.length - n;
  539. var r = stack.length - 1,
  540. c = l + (p - Math.floor(p / n) * n),
  541. i,
  542. j,
  543. t;
  544. for (i = l, j = r; i < j; i++, j--) {
  545. t = stack[i];
  546. stack[i] = stack[j];
  547. stack[j] = t;
  548. }
  549. for (i = l, j = c - 1; i < j; i++, j--) {
  550. t = stack[i];
  551. stack[i] = stack[j];
  552. stack[j] = t;
  553. }
  554. for (i = c, j = r; i < j; i++, j--) {
  555. t = stack[i];
  556. stack[i] = stack[j];
  557. stack[j] = t;
  558. }
  559. }
  560. };
  561. return PostScriptStack;
  562. }();
  563. var PostScriptEvaluator = function PostScriptEvaluatorClosure() {
  564. function PostScriptEvaluator(operators) {
  565. this.operators = operators;
  566. }
  567. PostScriptEvaluator.prototype = {
  568. execute: function PostScriptEvaluator_execute(initialStack) {
  569. var stack = new PostScriptStack(initialStack);
  570. var counter = 0;
  571. var operators = this.operators;
  572. var length = operators.length;
  573. var operator, a, b;
  574. while (counter < length) {
  575. operator = operators[counter++];
  576. if (typeof operator === 'number') {
  577. stack.push(operator);
  578. continue;
  579. }
  580. switch (operator) {
  581. case 'jz':
  582. b = stack.pop();
  583. a = stack.pop();
  584. if (!a) {
  585. counter = b;
  586. }
  587. break;
  588. case 'j':
  589. a = stack.pop();
  590. counter = a;
  591. break;
  592. case 'abs':
  593. a = stack.pop();
  594. stack.push(Math.abs(a));
  595. break;
  596. case 'add':
  597. b = stack.pop();
  598. a = stack.pop();
  599. stack.push(a + b);
  600. break;
  601. case 'and':
  602. b = stack.pop();
  603. a = stack.pop();
  604. if ((0, _util.isBool)(a) && (0, _util.isBool)(b)) {
  605. stack.push(a && b);
  606. } else {
  607. stack.push(a & b);
  608. }
  609. break;
  610. case 'atan':
  611. a = stack.pop();
  612. stack.push(Math.atan(a));
  613. break;
  614. case 'bitshift':
  615. b = stack.pop();
  616. a = stack.pop();
  617. if (a > 0) {
  618. stack.push(a << b);
  619. } else {
  620. stack.push(a >> b);
  621. }
  622. break;
  623. case 'ceiling':
  624. a = stack.pop();
  625. stack.push(Math.ceil(a));
  626. break;
  627. case 'copy':
  628. a = stack.pop();
  629. stack.copy(a);
  630. break;
  631. case 'cos':
  632. a = stack.pop();
  633. stack.push(Math.cos(a));
  634. break;
  635. case 'cvi':
  636. a = stack.pop() | 0;
  637. stack.push(a);
  638. break;
  639. case 'cvr':
  640. break;
  641. case 'div':
  642. b = stack.pop();
  643. a = stack.pop();
  644. stack.push(a / b);
  645. break;
  646. case 'dup':
  647. stack.copy(1);
  648. break;
  649. case 'eq':
  650. b = stack.pop();
  651. a = stack.pop();
  652. stack.push(a === b);
  653. break;
  654. case 'exch':
  655. stack.roll(2, 1);
  656. break;
  657. case 'exp':
  658. b = stack.pop();
  659. a = stack.pop();
  660. stack.push(Math.pow(a, b));
  661. break;
  662. case 'false':
  663. stack.push(false);
  664. break;
  665. case 'floor':
  666. a = stack.pop();
  667. stack.push(Math.floor(a));
  668. break;
  669. case 'ge':
  670. b = stack.pop();
  671. a = stack.pop();
  672. stack.push(a >= b);
  673. break;
  674. case 'gt':
  675. b = stack.pop();
  676. a = stack.pop();
  677. stack.push(a > b);
  678. break;
  679. case 'idiv':
  680. b = stack.pop();
  681. a = stack.pop();
  682. stack.push(a / b | 0);
  683. break;
  684. case 'index':
  685. a = stack.pop();
  686. stack.index(a);
  687. break;
  688. case 'le':
  689. b = stack.pop();
  690. a = stack.pop();
  691. stack.push(a <= b);
  692. break;
  693. case 'ln':
  694. a = stack.pop();
  695. stack.push(Math.log(a));
  696. break;
  697. case 'log':
  698. a = stack.pop();
  699. stack.push(Math.log(a) / Math.LN10);
  700. break;
  701. case 'lt':
  702. b = stack.pop();
  703. a = stack.pop();
  704. stack.push(a < b);
  705. break;
  706. case 'mod':
  707. b = stack.pop();
  708. a = stack.pop();
  709. stack.push(a % b);
  710. break;
  711. case 'mul':
  712. b = stack.pop();
  713. a = stack.pop();
  714. stack.push(a * b);
  715. break;
  716. case 'ne':
  717. b = stack.pop();
  718. a = stack.pop();
  719. stack.push(a !== b);
  720. break;
  721. case 'neg':
  722. a = stack.pop();
  723. stack.push(-a);
  724. break;
  725. case 'not':
  726. a = stack.pop();
  727. if ((0, _util.isBool)(a)) {
  728. stack.push(!a);
  729. } else {
  730. stack.push(~a);
  731. }
  732. break;
  733. case 'or':
  734. b = stack.pop();
  735. a = stack.pop();
  736. if ((0, _util.isBool)(a) && (0, _util.isBool)(b)) {
  737. stack.push(a || b);
  738. } else {
  739. stack.push(a | b);
  740. }
  741. break;
  742. case 'pop':
  743. stack.pop();
  744. break;
  745. case 'roll':
  746. b = stack.pop();
  747. a = stack.pop();
  748. stack.roll(a, b);
  749. break;
  750. case 'round':
  751. a = stack.pop();
  752. stack.push(Math.round(a));
  753. break;
  754. case 'sin':
  755. a = stack.pop();
  756. stack.push(Math.sin(a));
  757. break;
  758. case 'sqrt':
  759. a = stack.pop();
  760. stack.push(Math.sqrt(a));
  761. break;
  762. case 'sub':
  763. b = stack.pop();
  764. a = stack.pop();
  765. stack.push(a - b);
  766. break;
  767. case 'true':
  768. stack.push(true);
  769. break;
  770. case 'truncate':
  771. a = stack.pop();
  772. a = a < 0 ? Math.ceil(a) : Math.floor(a);
  773. stack.push(a);
  774. break;
  775. case 'xor':
  776. b = stack.pop();
  777. a = stack.pop();
  778. if ((0, _util.isBool)(a) && (0, _util.isBool)(b)) {
  779. stack.push(a !== b);
  780. } else {
  781. stack.push(a ^ b);
  782. }
  783. break;
  784. default:
  785. throw new _util.FormatError('Unknown operator ' + operator);
  786. }
  787. }
  788. return stack.stack;
  789. }
  790. };
  791. return PostScriptEvaluator;
  792. }();
  793. var PostScriptCompiler = function PostScriptCompilerClosure() {
  794. function AstNode(type) {
  795. this.type = type;
  796. }
  797. AstNode.prototype.visit = function (visitor) {
  798. (0, _util.unreachable)('abstract method');
  799. };
  800. function AstArgument(index, min, max) {
  801. AstNode.call(this, 'args');
  802. this.index = index;
  803. this.min = min;
  804. this.max = max;
  805. }
  806. AstArgument.prototype = Object.create(AstNode.prototype);
  807. AstArgument.prototype.visit = function (visitor) {
  808. visitor.visitArgument(this);
  809. };
  810. function AstLiteral(number) {
  811. AstNode.call(this, 'literal');
  812. this.number = number;
  813. this.min = number;
  814. this.max = number;
  815. }
  816. AstLiteral.prototype = Object.create(AstNode.prototype);
  817. AstLiteral.prototype.visit = function (visitor) {
  818. visitor.visitLiteral(this);
  819. };
  820. function AstBinaryOperation(op, arg1, arg2, min, max) {
  821. AstNode.call(this, 'binary');
  822. this.op = op;
  823. this.arg1 = arg1;
  824. this.arg2 = arg2;
  825. this.min = min;
  826. this.max = max;
  827. }
  828. AstBinaryOperation.prototype = Object.create(AstNode.prototype);
  829. AstBinaryOperation.prototype.visit = function (visitor) {
  830. visitor.visitBinaryOperation(this);
  831. };
  832. function AstMin(arg, max) {
  833. AstNode.call(this, 'max');
  834. this.arg = arg;
  835. this.min = arg.min;
  836. this.max = max;
  837. }
  838. AstMin.prototype = Object.create(AstNode.prototype);
  839. AstMin.prototype.visit = function (visitor) {
  840. visitor.visitMin(this);
  841. };
  842. function AstVariable(index, min, max) {
  843. AstNode.call(this, 'var');
  844. this.index = index;
  845. this.min = min;
  846. this.max = max;
  847. }
  848. AstVariable.prototype = Object.create(AstNode.prototype);
  849. AstVariable.prototype.visit = function (visitor) {
  850. visitor.visitVariable(this);
  851. };
  852. function AstVariableDefinition(variable, arg) {
  853. AstNode.call(this, 'definition');
  854. this.variable = variable;
  855. this.arg = arg;
  856. }
  857. AstVariableDefinition.prototype = Object.create(AstNode.prototype);
  858. AstVariableDefinition.prototype.visit = function (visitor) {
  859. visitor.visitVariableDefinition(this);
  860. };
  861. function ExpressionBuilderVisitor() {
  862. this.parts = [];
  863. }
  864. ExpressionBuilderVisitor.prototype = {
  865. visitArgument: function visitArgument(arg) {
  866. this.parts.push('Math.max(', arg.min, ', Math.min(', arg.max, ', src[srcOffset + ', arg.index, ']))');
  867. },
  868. visitVariable: function visitVariable(variable) {
  869. this.parts.push('v', variable.index);
  870. },
  871. visitLiteral: function visitLiteral(literal) {
  872. this.parts.push(literal.number);
  873. },
  874. visitBinaryOperation: function visitBinaryOperation(operation) {
  875. this.parts.push('(');
  876. operation.arg1.visit(this);
  877. this.parts.push(' ', operation.op, ' ');
  878. operation.arg2.visit(this);
  879. this.parts.push(')');
  880. },
  881. visitVariableDefinition: function visitVariableDefinition(definition) {
  882. this.parts.push('var ');
  883. definition.variable.visit(this);
  884. this.parts.push(' = ');
  885. definition.arg.visit(this);
  886. this.parts.push(';');
  887. },
  888. visitMin: function visitMin(max) {
  889. this.parts.push('Math.min(');
  890. max.arg.visit(this);
  891. this.parts.push(', ', max.max, ')');
  892. },
  893. toString: function toString() {
  894. return this.parts.join('');
  895. }
  896. };
  897. function buildAddOperation(num1, num2) {
  898. if (num2.type === 'literal' && num2.number === 0) {
  899. return num1;
  900. }
  901. if (num1.type === 'literal' && num1.number === 0) {
  902. return num2;
  903. }
  904. if (num2.type === 'literal' && num1.type === 'literal') {
  905. return new AstLiteral(num1.number + num2.number);
  906. }
  907. return new AstBinaryOperation('+', num1, num2, num1.min + num2.min, num1.max + num2.max);
  908. }
  909. function buildMulOperation(num1, num2) {
  910. if (num2.type === 'literal') {
  911. if (num2.number === 0) {
  912. return new AstLiteral(0);
  913. } else if (num2.number === 1) {
  914. return num1;
  915. } else if (num1.type === 'literal') {
  916. return new AstLiteral(num1.number * num2.number);
  917. }
  918. }
  919. if (num1.type === 'literal') {
  920. if (num1.number === 0) {
  921. return new AstLiteral(0);
  922. } else if (num1.number === 1) {
  923. return num2;
  924. }
  925. }
  926. var min = Math.min(num1.min * num2.min, num1.min * num2.max, num1.max * num2.min, num1.max * num2.max);
  927. var max = Math.max(num1.min * num2.min, num1.min * num2.max, num1.max * num2.min, num1.max * num2.max);
  928. return new AstBinaryOperation('*', num1, num2, min, max);
  929. }
  930. function buildSubOperation(num1, num2) {
  931. if (num2.type === 'literal') {
  932. if (num2.number === 0) {
  933. return num1;
  934. } else if (num1.type === 'literal') {
  935. return new AstLiteral(num1.number - num2.number);
  936. }
  937. }
  938. if (num2.type === 'binary' && num2.op === '-' && num1.type === 'literal' && num1.number === 1 && num2.arg1.type === 'literal' && num2.arg1.number === 1) {
  939. return num2.arg2;
  940. }
  941. return new AstBinaryOperation('-', num1, num2, num1.min - num2.max, num1.max - num2.min);
  942. }
  943. function buildMinOperation(num1, max) {
  944. if (num1.min >= max) {
  945. return new AstLiteral(max);
  946. } else if (num1.max <= max) {
  947. return num1;
  948. }
  949. return new AstMin(num1, max);
  950. }
  951. function PostScriptCompiler() {}
  952. PostScriptCompiler.prototype = {
  953. compile: function PostScriptCompiler_compile(code, domain, range) {
  954. var stack = [];
  955. var i, ii;
  956. var instructions = [];
  957. var inputSize = domain.length >> 1,
  958. outputSize = range.length >> 1;
  959. var lastRegister = 0;
  960. var n, j;
  961. var num1, num2, ast1, ast2, tmpVar, item;
  962. for (i = 0; i < inputSize; i++) {
  963. stack.push(new AstArgument(i, domain[i * 2], domain[i * 2 + 1]));
  964. }
  965. for (i = 0, ii = code.length; i < ii; i++) {
  966. item = code[i];
  967. if (typeof item === 'number') {
  968. stack.push(new AstLiteral(item));
  969. continue;
  970. }
  971. switch (item) {
  972. case 'add':
  973. if (stack.length < 2) {
  974. return null;
  975. }
  976. num2 = stack.pop();
  977. num1 = stack.pop();
  978. stack.push(buildAddOperation(num1, num2));
  979. break;
  980. case 'cvr':
  981. if (stack.length < 1) {
  982. return null;
  983. }
  984. break;
  985. case 'mul':
  986. if (stack.length < 2) {
  987. return null;
  988. }
  989. num2 = stack.pop();
  990. num1 = stack.pop();
  991. stack.push(buildMulOperation(num1, num2));
  992. break;
  993. case 'sub':
  994. if (stack.length < 2) {
  995. return null;
  996. }
  997. num2 = stack.pop();
  998. num1 = stack.pop();
  999. stack.push(buildSubOperation(num1, num2));
  1000. break;
  1001. case 'exch':
  1002. if (stack.length < 2) {
  1003. return null;
  1004. }
  1005. ast1 = stack.pop();
  1006. ast2 = stack.pop();
  1007. stack.push(ast1, ast2);
  1008. break;
  1009. case 'pop':
  1010. if (stack.length < 1) {
  1011. return null;
  1012. }
  1013. stack.pop();
  1014. break;
  1015. case 'index':
  1016. if (stack.length < 1) {
  1017. return null;
  1018. }
  1019. num1 = stack.pop();
  1020. if (num1.type !== 'literal') {
  1021. return null;
  1022. }
  1023. n = num1.number;
  1024. if (n < 0 || !Number.isInteger(n) || stack.length < n) {
  1025. return null;
  1026. }
  1027. ast1 = stack[stack.length - n - 1];
  1028. if (ast1.type === 'literal' || ast1.type === 'var') {
  1029. stack.push(ast1);
  1030. break;
  1031. }
  1032. tmpVar = new AstVariable(lastRegister++, ast1.min, ast1.max);
  1033. stack[stack.length - n - 1] = tmpVar;
  1034. stack.push(tmpVar);
  1035. instructions.push(new AstVariableDefinition(tmpVar, ast1));
  1036. break;
  1037. case 'dup':
  1038. if (stack.length < 1) {
  1039. return null;
  1040. }
  1041. 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]) {
  1042. num1 = stack.pop();
  1043. stack.push(buildMinOperation(num1, code[i + 1]));
  1044. i += 6;
  1045. break;
  1046. }
  1047. ast1 = stack[stack.length - 1];
  1048. if (ast1.type === 'literal' || ast1.type === 'var') {
  1049. stack.push(ast1);
  1050. break;
  1051. }
  1052. tmpVar = new AstVariable(lastRegister++, ast1.min, ast1.max);
  1053. stack[stack.length - 1] = tmpVar;
  1054. stack.push(tmpVar);
  1055. instructions.push(new AstVariableDefinition(tmpVar, ast1));
  1056. break;
  1057. case 'roll':
  1058. if (stack.length < 2) {
  1059. return null;
  1060. }
  1061. num2 = stack.pop();
  1062. num1 = stack.pop();
  1063. if (num2.type !== 'literal' || num1.type !== 'literal') {
  1064. return null;
  1065. }
  1066. j = num2.number;
  1067. n = num1.number;
  1068. if (n <= 0 || !Number.isInteger(n) || !Number.isInteger(j) || stack.length < n) {
  1069. return null;
  1070. }
  1071. j = (j % n + n) % n;
  1072. if (j === 0) {
  1073. break;
  1074. }
  1075. Array.prototype.push.apply(stack, stack.splice(stack.length - n, n - j));
  1076. break;
  1077. default:
  1078. return null;
  1079. }
  1080. }
  1081. if (stack.length !== outputSize) {
  1082. return null;
  1083. }
  1084. var result = [];
  1085. instructions.forEach(function (instruction) {
  1086. var statementBuilder = new ExpressionBuilderVisitor();
  1087. instruction.visit(statementBuilder);
  1088. result.push(statementBuilder.toString());
  1089. });
  1090. stack.forEach(function (expr, i) {
  1091. var statementBuilder = new ExpressionBuilderVisitor();
  1092. expr.visit(statementBuilder);
  1093. var min = range[i * 2],
  1094. max = range[i * 2 + 1];
  1095. var out = [statementBuilder.toString()];
  1096. if (min > expr.min) {
  1097. out.unshift('Math.max(', min, ', ');
  1098. out.push(')');
  1099. }
  1100. if (max < expr.max) {
  1101. out.unshift('Math.min(', max, ', ');
  1102. out.push(')');
  1103. }
  1104. out.unshift('dest[destOffset + ', i, '] = ');
  1105. out.push(';');
  1106. result.push(out.join(''));
  1107. });
  1108. return result.join('\n');
  1109. }
  1110. };
  1111. return PostScriptCompiler;
  1112. }();
  1113. exports.isPDFFunction = isPDFFunction;
  1114. exports.PDFFunctionFactory = PDFFunctionFactory;
  1115. exports.PostScriptEvaluator = PostScriptEvaluator;
  1116. exports.PostScriptCompiler = PostScriptCompiler;