evaluator_spec.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. /**
  2. * @licstart The following is the entire license notice for the
  3. * Javascript code in this page
  4. *
  5. * Copyright 2020 Mozilla Foundation
  6. *
  7. * Licensed under the Apache License, Version 2.0 (the "License");
  8. * you may not use this file except in compliance with the License.
  9. * You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing, software
  14. * distributed under the License is distributed on an "AS IS" BASIS,
  15. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16. * See the License for the specific language governing permissions and
  17. * limitations under the License.
  18. *
  19. * @licend The above is the entire license notice for the
  20. * Javascript code in this page
  21. */
  22. "use strict";
  23. var _test_utils = require("./test_utils.js");
  24. var _primitives = require("../../core/primitives.js");
  25. var _util = require("../../shared/util.js");
  26. var _stream = require("../../core/stream.js");
  27. var _operator_list = require("../../core/operator_list.js");
  28. var _evaluator = require("../../core/evaluator.js");
  29. var _worker = require("../../core/worker.js");
  30. describe("evaluator", function () {
  31. function HandlerMock() {
  32. this.inputs = [];
  33. }
  34. HandlerMock.prototype = {
  35. send(name, data) {
  36. this.inputs.push({
  37. name,
  38. data
  39. });
  40. }
  41. };
  42. function ResourcesMock() {}
  43. ResourcesMock.prototype = {
  44. get(name) {
  45. return this[name];
  46. }
  47. };
  48. function runOperatorListCheck(evaluator, stream, resources, callback) {
  49. var result = new _operator_list.OperatorList();
  50. var task = new _worker.WorkerTask("OperatorListCheck");
  51. evaluator.getOperatorList({
  52. stream,
  53. task,
  54. resources,
  55. operatorList: result
  56. }).then(function () {
  57. callback(result);
  58. }, function (reason) {
  59. callback(reason);
  60. });
  61. }
  62. var partialEvaluator;
  63. beforeAll(function (done) {
  64. partialEvaluator = new _evaluator.PartialEvaluator({
  65. xref: new _test_utils.XRefMock(),
  66. handler: new HandlerMock(),
  67. pageIndex: 0,
  68. idFactory: (0, _test_utils.createIdFactory)(0)
  69. });
  70. done();
  71. });
  72. afterAll(function () {
  73. partialEvaluator = null;
  74. });
  75. describe("splitCombinedOperations", function () {
  76. it("should reject unknown operations", function (done) {
  77. var stream = new _stream.StringStream("fTT");
  78. runOperatorListCheck(partialEvaluator, stream, new ResourcesMock(), function (result) {
  79. expect(!!result.fnArray && !!result.argsArray).toEqual(true);
  80. expect(result.fnArray.length).toEqual(1);
  81. expect(result.fnArray[0]).toEqual(_util.OPS.fill);
  82. expect(result.argsArray[0]).toEqual(null);
  83. done();
  84. });
  85. });
  86. it("should handle one operation", function (done) {
  87. var stream = new _stream.StringStream("Q");
  88. runOperatorListCheck(partialEvaluator, stream, new ResourcesMock(), function (result) {
  89. expect(!!result.fnArray && !!result.argsArray).toEqual(true);
  90. expect(result.fnArray.length).toEqual(1);
  91. expect(result.fnArray[0]).toEqual(_util.OPS.restore);
  92. done();
  93. });
  94. });
  95. it("should handle two glued operations", function (done) {
  96. const imgDict = new _primitives.Dict();
  97. imgDict.set("Subtype", _primitives.Name.get("Image"));
  98. imgDict.set("Width", 1);
  99. imgDict.set("Height", 1);
  100. const imgStream = new _stream.Stream([0]);
  101. imgStream.dict = imgDict;
  102. const xObject = new _primitives.Dict();
  103. xObject.set("Res1", imgStream);
  104. const resources = new ResourcesMock();
  105. resources.XObject = xObject;
  106. var stream = new _stream.StringStream("/Res1 DoQ");
  107. runOperatorListCheck(partialEvaluator, stream, resources, function (result) {
  108. expect(result.fnArray.length).toEqual(3);
  109. expect(result.fnArray[0]).toEqual(_util.OPS.dependency);
  110. expect(result.fnArray[1]).toEqual(_util.OPS.paintImageXObject);
  111. expect(result.fnArray[2]).toEqual(_util.OPS.restore);
  112. expect(result.argsArray.length).toEqual(3);
  113. expect(result.argsArray[0]).toEqual(["img_p0_1"]);
  114. expect(result.argsArray[1]).toEqual(["img_p0_1", 1, 1]);
  115. expect(result.argsArray[2]).toEqual(null);
  116. done();
  117. });
  118. });
  119. it("should handle three glued operations", function (done) {
  120. var stream = new _stream.StringStream("fff");
  121. runOperatorListCheck(partialEvaluator, stream, new ResourcesMock(), function (result) {
  122. expect(!!result.fnArray && !!result.argsArray).toEqual(true);
  123. expect(result.fnArray.length).toEqual(3);
  124. expect(result.fnArray[0]).toEqual(_util.OPS.fill);
  125. expect(result.fnArray[1]).toEqual(_util.OPS.fill);
  126. expect(result.fnArray[2]).toEqual(_util.OPS.fill);
  127. done();
  128. });
  129. });
  130. it("should handle three glued operations #2", function (done) {
  131. var resources = new ResourcesMock();
  132. resources.Res1 = {};
  133. var stream = new _stream.StringStream("B*Bf*");
  134. runOperatorListCheck(partialEvaluator, stream, resources, function (result) {
  135. expect(!!result.fnArray && !!result.argsArray).toEqual(true);
  136. expect(result.fnArray.length).toEqual(3);
  137. expect(result.fnArray[0]).toEqual(_util.OPS.eoFillStroke);
  138. expect(result.fnArray[1]).toEqual(_util.OPS.fillStroke);
  139. expect(result.fnArray[2]).toEqual(_util.OPS.eoFill);
  140. done();
  141. });
  142. });
  143. it("should handle glued operations and operands", function (done) {
  144. var stream = new _stream.StringStream("f5 Ts");
  145. runOperatorListCheck(partialEvaluator, stream, new ResourcesMock(), function (result) {
  146. expect(!!result.fnArray && !!result.argsArray).toEqual(true);
  147. expect(result.fnArray.length).toEqual(2);
  148. expect(result.fnArray[0]).toEqual(_util.OPS.fill);
  149. expect(result.fnArray[1]).toEqual(_util.OPS.setTextRise);
  150. expect(result.argsArray.length).toEqual(2);
  151. expect(result.argsArray[1].length).toEqual(1);
  152. expect(result.argsArray[1][0]).toEqual(5);
  153. done();
  154. });
  155. });
  156. it("should handle glued operations and literals", function (done) {
  157. var stream = new _stream.StringStream("trueifalserinulln");
  158. runOperatorListCheck(partialEvaluator, stream, new ResourcesMock(), function (result) {
  159. expect(!!result.fnArray && !!result.argsArray).toEqual(true);
  160. expect(result.fnArray.length).toEqual(3);
  161. expect(result.fnArray[0]).toEqual(_util.OPS.setFlatness);
  162. expect(result.fnArray[1]).toEqual(_util.OPS.setRenderingIntent);
  163. expect(result.fnArray[2]).toEqual(_util.OPS.endPath);
  164. expect(result.argsArray.length).toEqual(3);
  165. expect(result.argsArray[0].length).toEqual(1);
  166. expect(result.argsArray[0][0]).toEqual(true);
  167. expect(result.argsArray[1].length).toEqual(1);
  168. expect(result.argsArray[1][0]).toEqual(false);
  169. expect(result.argsArray[2]).toEqual(null);
  170. done();
  171. });
  172. });
  173. });
  174. describe("validateNumberOfArgs", function () {
  175. it("should execute if correct number of arguments", function (done) {
  176. var stream = new _stream.StringStream("5 1 d0");
  177. runOperatorListCheck(partialEvaluator, stream, new ResourcesMock(), function (result) {
  178. expect(result.argsArray[0][0]).toEqual(5);
  179. expect(result.argsArray[0][1]).toEqual(1);
  180. expect(result.fnArray[0]).toEqual(_util.OPS.setCharWidth);
  181. done();
  182. });
  183. });
  184. it("should execute if too many arguments", function (done) {
  185. var stream = new _stream.StringStream("5 1 4 d0");
  186. runOperatorListCheck(partialEvaluator, stream, new ResourcesMock(), function (result) {
  187. expect(result.argsArray[0][0]).toEqual(1);
  188. expect(result.argsArray[0][1]).toEqual(4);
  189. expect(result.fnArray[0]).toEqual(_util.OPS.setCharWidth);
  190. done();
  191. });
  192. });
  193. it("should execute if nested commands", function (done) {
  194. const gState = new _primitives.Dict();
  195. gState.set("LW", 2);
  196. gState.set("CA", 0.5);
  197. const extGState = new _primitives.Dict();
  198. extGState.set("GS2", gState);
  199. const resources = new ResourcesMock();
  200. resources.ExtGState = extGState;
  201. var stream = new _stream.StringStream("/F2 /GS2 gs 5.711 Tf");
  202. runOperatorListCheck(partialEvaluator, stream, resources, function (result) {
  203. expect(result.fnArray.length).toEqual(3);
  204. expect(result.fnArray[0]).toEqual(_util.OPS.setGState);
  205. expect(result.fnArray[1]).toEqual(_util.OPS.dependency);
  206. expect(result.fnArray[2]).toEqual(_util.OPS.setFont);
  207. expect(result.argsArray.length).toEqual(3);
  208. expect(result.argsArray[0]).toEqual([[["LW", 2], ["CA", 0.5]]]);
  209. expect(result.argsArray[1]).toEqual(["g_font_error"]);
  210. expect(result.argsArray[2]).toEqual(["g_font_error", 5.711]);
  211. done();
  212. });
  213. });
  214. it("should skip if too few arguments", function (done) {
  215. var stream = new _stream.StringStream("5 d0");
  216. runOperatorListCheck(partialEvaluator, stream, new ResourcesMock(), function (result) {
  217. expect(result.argsArray).toEqual([]);
  218. expect(result.fnArray).toEqual([]);
  219. done();
  220. });
  221. });
  222. it("should error if (many) path operators have too few arguments " + "(bug 1443140)", function (done) {
  223. const NUM_INVALID_OPS = 25;
  224. const tempArr = new Array(NUM_INVALID_OPS + 1);
  225. const invalidMoveText = tempArr.join("10 Td\n");
  226. const moveTextStream = new _stream.StringStream(invalidMoveText);
  227. runOperatorListCheck(partialEvaluator, moveTextStream, new ResourcesMock(), function (result) {
  228. expect(result.argsArray).toEqual([]);
  229. expect(result.fnArray).toEqual([]);
  230. done();
  231. });
  232. const invalidLineTo = tempArr.join("20 l\n");
  233. const lineToStream = new _stream.StringStream(invalidLineTo);
  234. runOperatorListCheck(partialEvaluator, lineToStream, new ResourcesMock(), function (error) {
  235. expect(error instanceof _util.FormatError).toEqual(true);
  236. expect(error.message).toEqual("Invalid command l: expected 2 args, but received 1 args.");
  237. done();
  238. });
  239. });
  240. it("should close opened saves", function (done) {
  241. var stream = new _stream.StringStream("qq");
  242. runOperatorListCheck(partialEvaluator, stream, new ResourcesMock(), function (result) {
  243. expect(!!result.fnArray && !!result.argsArray).toEqual(true);
  244. expect(result.fnArray.length).toEqual(4);
  245. expect(result.fnArray[0]).toEqual(_util.OPS.save);
  246. expect(result.fnArray[1]).toEqual(_util.OPS.save);
  247. expect(result.fnArray[2]).toEqual(_util.OPS.restore);
  248. expect(result.fnArray[3]).toEqual(_util.OPS.restore);
  249. done();
  250. });
  251. });
  252. it("should error on paintXObject if name is missing", function (done) {
  253. var stream = new _stream.StringStream("/ Do");
  254. runOperatorListCheck(partialEvaluator, stream, new ResourcesMock(), function (result) {
  255. expect(result instanceof _util.FormatError).toEqual(true);
  256. expect(result.message).toEqual("XObject must be referred to by name.");
  257. done();
  258. });
  259. });
  260. it("should skip paintXObject if subtype is PS", function (done) {
  261. var xobjStreamDict = new _primitives.Dict();
  262. xobjStreamDict.set("Subtype", _primitives.Name.get("PS"));
  263. var xobjStream = new _stream.Stream([], 0, 0, xobjStreamDict);
  264. var xobjs = new _primitives.Dict();
  265. xobjs.set("Res1", xobjStream);
  266. var resources = new _primitives.Dict();
  267. resources.set("XObject", xobjs);
  268. var stream = new _stream.StringStream("/Res1 Do");
  269. runOperatorListCheck(partialEvaluator, stream, resources, function (result) {
  270. expect(result.argsArray).toEqual([]);
  271. expect(result.fnArray).toEqual([]);
  272. done();
  273. });
  274. });
  275. });
  276. describe("thread control", function () {
  277. it("should abort operator list parsing", function (done) {
  278. var stream = new _stream.StringStream("qqQQ");
  279. var resources = new ResourcesMock();
  280. var result = new _operator_list.OperatorList();
  281. var task = new _worker.WorkerTask("OperatorListAbort");
  282. task.terminate();
  283. partialEvaluator.getOperatorList({
  284. stream,
  285. task,
  286. resources,
  287. operatorList: result
  288. }).catch(function () {
  289. expect(!!result.fnArray && !!result.argsArray).toEqual(true);
  290. expect(result.fnArray.length).toEqual(0);
  291. done();
  292. });
  293. });
  294. it("should abort text parsing parsing", function (done) {
  295. var resources = new ResourcesMock();
  296. var stream = new _stream.StringStream("qqQQ");
  297. var task = new _worker.WorkerTask("TextContentAbort");
  298. task.terminate();
  299. partialEvaluator.getTextContent({
  300. stream,
  301. task,
  302. resources
  303. }).catch(function () {
  304. expect(true).toEqual(true);
  305. done();
  306. });
  307. });
  308. });
  309. describe("operator list", function () {
  310. class StreamSinkMock {
  311. enqueue() {}
  312. }
  313. it("should get correct total length after flushing", function () {
  314. var operatorList = new _operator_list.OperatorList(null, new StreamSinkMock());
  315. operatorList.addOp(_util.OPS.save, null);
  316. operatorList.addOp(_util.OPS.restore, null);
  317. expect(operatorList.totalLength).toEqual(2);
  318. expect(operatorList.length).toEqual(2);
  319. operatorList.flush();
  320. expect(operatorList.totalLength).toEqual(2);
  321. expect(operatorList.length).toEqual(0);
  322. });
  323. });
  324. });