evaluator_spec.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  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. var coreEvaluator = require('../../core/evaluator.js');
  17. var corePrimitives = require('../../core/primitives.js');
  18. var coreStream = require('../../core/stream.js');
  19. var coreWorker = require('../../core/worker.js');
  20. var sharedUtil = require('../../shared/util.js');
  21. var OperatorList = coreEvaluator.OperatorList;
  22. var PartialEvaluator = coreEvaluator.PartialEvaluator;
  23. var Dict = corePrimitives.Dict;
  24. var Name = corePrimitives.Name;
  25. var Stream = coreStream.Stream;
  26. var StringStream = coreStream.StringStream;
  27. var WorkerTask = coreWorker.WorkerTask;
  28. var OPS = sharedUtil.OPS;
  29. describe('evaluator', function () {
  30. function XrefMock(queue) {
  31. this.queue = queue || [];
  32. }
  33. XrefMock.prototype = {
  34. fetchIfRef: function () {
  35. return this.queue.shift();
  36. }
  37. };
  38. function HandlerMock() {
  39. this.inputs = [];
  40. }
  41. HandlerMock.prototype = {
  42. send: function (name, data) {
  43. this.inputs.push({
  44. name: name,
  45. data: data
  46. });
  47. }
  48. };
  49. function ResourcesMock() {
  50. }
  51. ResourcesMock.prototype = {
  52. get: function (name) {
  53. return this[name];
  54. }
  55. };
  56. function PdfManagerMock() {
  57. }
  58. function runOperatorListCheck(evaluator, stream, resources, callback) {
  59. var result = new OperatorList();
  60. var task = new WorkerTask('OperatorListCheck');
  61. evaluator.getOperatorList(stream, task, resources, result).then(function () {
  62. callback(result);
  63. });
  64. }
  65. describe('splitCombinedOperations', function () {
  66. it('should reject unknown operations', function (done) {
  67. var evaluator = new PartialEvaluator(new PdfManagerMock(), new XrefMock(), new HandlerMock(), 'prefix');
  68. var stream = new StringStream('fTT');
  69. runOperatorListCheck(evaluator, stream, new ResourcesMock(), function (result) {
  70. expect(!!result.fnArray && !!result.argsArray).toEqual(true);
  71. expect(result.fnArray.length).toEqual(1);
  72. expect(result.fnArray[0]).toEqual(OPS.fill);
  73. expect(result.argsArray[0]).toEqual(null);
  74. done();
  75. });
  76. });
  77. it('should handle one operations', function (done) {
  78. var evaluator = new PartialEvaluator(new PdfManagerMock(), new XrefMock(), new HandlerMock(), 'prefix');
  79. var stream = new StringStream('Q');
  80. runOperatorListCheck(evaluator, stream, new ResourcesMock(), function (result) {
  81. expect(!!result.fnArray && !!result.argsArray).toEqual(true);
  82. expect(result.fnArray.length).toEqual(1);
  83. expect(result.fnArray[0]).toEqual(OPS.restore);
  84. done();
  85. });
  86. });
  87. it('should handle two glued operations', function (done) {
  88. var evaluator = new PartialEvaluator(new PdfManagerMock(), new XrefMock(), new HandlerMock(), 'prefix');
  89. var resources = new ResourcesMock();
  90. resources.Res1 = {};
  91. var stream = new StringStream('/Res1 DoQ');
  92. runOperatorListCheck(evaluator, stream, resources, function (result) {
  93. expect(!!result.fnArray && !!result.argsArray).toEqual(true);
  94. expect(result.fnArray.length).toEqual(2);
  95. expect(result.fnArray[0]).toEqual(OPS.paintXObject);
  96. expect(result.fnArray[1]).toEqual(OPS.restore);
  97. done();
  98. });
  99. });
  100. it('should handle tree glued operations', function (done) {
  101. var evaluator = new PartialEvaluator(new PdfManagerMock(), new XrefMock(), new HandlerMock(), 'prefix');
  102. var stream = new StringStream('fff');
  103. runOperatorListCheck(evaluator, stream, new ResourcesMock(), function (result) {
  104. expect(!!result.fnArray && !!result.argsArray).toEqual(true);
  105. expect(result.fnArray.length).toEqual(3);
  106. expect(result.fnArray[0]).toEqual(OPS.fill);
  107. expect(result.fnArray[1]).toEqual(OPS.fill);
  108. expect(result.fnArray[2]).toEqual(OPS.fill);
  109. done();
  110. });
  111. });
  112. it('should handle three glued operations #2', function (done) {
  113. var evaluator = new PartialEvaluator(new PdfManagerMock(), new XrefMock(), new HandlerMock(), 'prefix');
  114. var resources = new ResourcesMock();
  115. resources.Res1 = {};
  116. var stream = new StringStream('B*Bf*');
  117. runOperatorListCheck(evaluator, stream, resources, function (result) {
  118. expect(!!result.fnArray && !!result.argsArray).toEqual(true);
  119. expect(result.fnArray.length).toEqual(3);
  120. expect(result.fnArray[0]).toEqual(OPS.eoFillStroke);
  121. expect(result.fnArray[1]).toEqual(OPS.fillStroke);
  122. expect(result.fnArray[2]).toEqual(OPS.eoFill);
  123. done();
  124. });
  125. });
  126. it('should handle glued operations and operands', function (done) {
  127. var evaluator = new PartialEvaluator(new PdfManagerMock(), new XrefMock(), new HandlerMock(), 'prefix');
  128. var stream = new StringStream('f5 Ts');
  129. runOperatorListCheck(evaluator, stream, new ResourcesMock(), function (result) {
  130. expect(!!result.fnArray && !!result.argsArray).toEqual(true);
  131. expect(result.fnArray.length).toEqual(2);
  132. expect(result.fnArray[0]).toEqual(OPS.fill);
  133. expect(result.fnArray[1]).toEqual(OPS.setTextRise);
  134. expect(result.argsArray.length).toEqual(2);
  135. expect(result.argsArray[1].length).toEqual(1);
  136. expect(result.argsArray[1][0]).toEqual(5);
  137. done();
  138. });
  139. });
  140. it('should handle glued operations and literals', function (done) {
  141. var evaluator = new PartialEvaluator(new PdfManagerMock(), new XrefMock(), new HandlerMock(), 'prefix');
  142. var stream = new StringStream('trueifalserinulln');
  143. runOperatorListCheck(evaluator, stream, new ResourcesMock(), function (result) {
  144. expect(!!result.fnArray && !!result.argsArray).toEqual(true);
  145. expect(result.fnArray.length).toEqual(3);
  146. expect(result.fnArray[0]).toEqual(OPS.setFlatness);
  147. expect(result.fnArray[1]).toEqual(OPS.setRenderingIntent);
  148. expect(result.fnArray[2]).toEqual(OPS.endPath);
  149. expect(result.argsArray.length).toEqual(3);
  150. expect(result.argsArray[0].length).toEqual(1);
  151. expect(result.argsArray[0][0]).toEqual(true);
  152. expect(result.argsArray[1].length).toEqual(1);
  153. expect(result.argsArray[1][0]).toEqual(false);
  154. expect(result.argsArray[2]).toEqual(null);
  155. done();
  156. });
  157. });
  158. });
  159. describe('validateNumberOfArgs', function () {
  160. it('should execute if correct number of arguments', function (done) {
  161. var evaluator = new PartialEvaluator(new PdfManagerMock(), new XrefMock(), new HandlerMock(), 'prefix');
  162. var stream = new StringStream('5 1 d0');
  163. runOperatorListCheck(evaluator, stream, new ResourcesMock(), function (result) {
  164. expect(result.argsArray[0][0]).toEqual(5);
  165. expect(result.argsArray[0][1]).toEqual(1);
  166. expect(result.fnArray[0]).toEqual(OPS.setCharWidth);
  167. done();
  168. });
  169. });
  170. it('should execute if too many arguments', function (done) {
  171. var evaluator = new PartialEvaluator(new PdfManagerMock(), new XrefMock(), new HandlerMock(), 'prefix');
  172. var stream = new StringStream('5 1 4 d0');
  173. runOperatorListCheck(evaluator, stream, new ResourcesMock(), function (result) {
  174. expect(result.argsArray[0][0]).toEqual(1);
  175. expect(result.argsArray[0][1]).toEqual(4);
  176. expect(result.fnArray[0]).toEqual(OPS.setCharWidth);
  177. done();
  178. });
  179. });
  180. it('should execute if nested commands', function (done) {
  181. var evaluator = new PartialEvaluator(new PdfManagerMock(), new XrefMock(), new HandlerMock(), 'prefix');
  182. var stream = new StringStream('/F2 /GS2 gs 5.711 Tf');
  183. runOperatorListCheck(evaluator, stream, new ResourcesMock(), function (result) {
  184. expect(result.fnArray.length).toEqual(3);
  185. expect(result.fnArray[0]).toEqual(OPS.setGState);
  186. expect(result.fnArray[1]).toEqual(OPS.dependency);
  187. expect(result.fnArray[2]).toEqual(OPS.setFont);
  188. expect(result.argsArray.length).toEqual(3);
  189. expect(result.argsArray[0].length).toEqual(1);
  190. expect(result.argsArray[1].length).toEqual(1);
  191. expect(result.argsArray[2].length).toEqual(2);
  192. done();
  193. });
  194. });
  195. it('should skip if too few arguments', function (done) {
  196. var evaluator = new PartialEvaluator(new PdfManagerMock(), new XrefMock(), new HandlerMock(), 'prefix');
  197. var stream = new StringStream('5 d0');
  198. runOperatorListCheck(evaluator, stream, new ResourcesMock(), function (result) {
  199. expect(result.argsArray).toEqual([]);
  200. expect(result.fnArray).toEqual([]);
  201. done();
  202. });
  203. });
  204. it('should close opened saves', function (done) {
  205. var evaluator = new PartialEvaluator(new PdfManagerMock(), new XrefMock(), new HandlerMock(), 'prefix');
  206. var stream = new StringStream('qq');
  207. runOperatorListCheck(evaluator, stream, new ResourcesMock(), function (result) {
  208. expect(!!result.fnArray && !!result.argsArray).toEqual(true);
  209. expect(result.fnArray.length).toEqual(4);
  210. expect(result.fnArray[0]).toEqual(OPS.save);
  211. expect(result.fnArray[1]).toEqual(OPS.save);
  212. expect(result.fnArray[2]).toEqual(OPS.restore);
  213. expect(result.fnArray[3]).toEqual(OPS.restore);
  214. done();
  215. });
  216. });
  217. it('should skip paintXObject if name is missing', function (done) {
  218. var evaluator = new PartialEvaluator(new PdfManagerMock(), new XrefMock(), new HandlerMock(), 'prefix');
  219. var stream = new StringStream('/ Do');
  220. runOperatorListCheck(evaluator, stream, new ResourcesMock(), function (result) {
  221. expect(result.argsArray).toEqual([]);
  222. expect(result.fnArray).toEqual([]);
  223. done();
  224. });
  225. });
  226. it('should skip paintXObject if subtype is PS', function (done) {
  227. var evaluator = new PartialEvaluator(new PdfManagerMock(), new XrefMock(), new HandlerMock(), 'prefix');
  228. var xobjStreamDict = new Dict();
  229. xobjStreamDict.set('Subtype', Name.get('PS'));
  230. var xobjStream = new Stream([], 0, 0, xobjStreamDict);
  231. var xobjs = new Dict();
  232. xobjs.set('Res1', xobjStream);
  233. var resources = new Dict();
  234. resources.set('XObject', xobjs);
  235. var stream = new StringStream('/Res1 Do');
  236. runOperatorListCheck(evaluator, stream, resources, function (result) {
  237. expect(result.argsArray).toEqual([]);
  238. expect(result.fnArray).toEqual([]);
  239. done();
  240. });
  241. });
  242. });
  243. describe('thread control', function () {
  244. it('should abort operator list parsing', function (done) {
  245. var evaluator = new PartialEvaluator(new PdfManagerMock(), new XrefMock(), new HandlerMock(), 'prefix');
  246. var stream = new StringStream('qqQQ');
  247. var resources = new ResourcesMock();
  248. var result = new OperatorList();
  249. var task = new WorkerTask('OperatorListAbort');
  250. task.terminate();
  251. evaluator.getOperatorList(stream, task, resources, result).catch(function () {
  252. expect(!!result.fnArray && !!result.argsArray).toEqual(true);
  253. expect(result.fnArray.length).toEqual(0);
  254. done();
  255. });
  256. });
  257. it('should abort text parsing parsing', function (done) {
  258. var resources = new ResourcesMock();
  259. var evaluator = new PartialEvaluator(new PdfManagerMock(), new XrefMock(), new HandlerMock(), 'prefix');
  260. var stream = new StringStream('qqQQ');
  261. var task = new WorkerTask('TextContentAbort');
  262. task.terminate();
  263. evaluator.getTextContent(stream, task, resources).catch(function () {
  264. expect(true).toEqual(true);
  265. done();
  266. });
  267. });
  268. });
  269. describe('operator list', function () {
  270. function MessageHandlerMock() {
  271. }
  272. MessageHandlerMock.prototype = {
  273. send: function () {
  274. }
  275. };
  276. it('should get correct total length after flushing', function () {
  277. var operatorList = new OperatorList(null, new MessageHandlerMock());
  278. operatorList.addOp(OPS.save, null);
  279. operatorList.addOp(OPS.restore, null);
  280. expect(operatorList.totalLength).toEqual(2);
  281. expect(operatorList.length).toEqual(2);
  282. operatorList.flush();
  283. expect(operatorList.totalLength).toEqual(2);
  284. expect(operatorList.length).toEqual(0);
  285. });
  286. });
  287. });