api_spec.js 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035
  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 sharedUtil = require('../../shared/util.js');
  17. var displayGlobal = require('../../display/global.js');
  18. var displayApi = require('../../display/api.js');
  19. var PDFJS = displayGlobal.PDFJS;
  20. var createPromiseCapability = sharedUtil.createPromiseCapability;
  21. var PDFDocumentProxy = displayApi.PDFDocumentProxy;
  22. var InvalidPDFException = sharedUtil.InvalidPDFException;
  23. var MissingPDFException = sharedUtil.MissingPDFException;
  24. var PasswordResponses = sharedUtil.PasswordResponses;
  25. var PasswordException = sharedUtil.PasswordException;
  26. var PDFPageProxy = displayApi.PDFPageProxy;
  27. var StreamType = sharedUtil.StreamType;
  28. var FontType = sharedUtil.FontType;
  29. describe('api', function () {
  30. var basicApiUrl = new URL('../pdfs/basicapi.pdf', window.location).href;
  31. var basicApiFileLength = 105779;
  32. function waitSome(callback) {
  33. var WAIT_TIMEOUT = 10;
  34. setTimeout(function () {
  35. callback();
  36. }, WAIT_TIMEOUT);
  37. }
  38. describe('PDFJS', function () {
  39. describe('getDocument', function () {
  40. it('creates pdf doc from URL', function (done) {
  41. var loadingTask = PDFJS.getDocument(basicApiUrl);
  42. var isProgressReportedResolved = false;
  43. var progressReportedCapability = createPromiseCapability();
  44. loadingTask.onProgress = function (progressData) {
  45. if (!isProgressReportedResolved) {
  46. isProgressReportedResolved = true;
  47. progressReportedCapability.resolve(progressData);
  48. }
  49. };
  50. var promises = [progressReportedCapability.promise, loadingTask.promise];
  51. Promise.all(promises).then(function (data) {
  52. expect(data[0].loaded / data[0].total > 0).toEqual(true);
  53. expect(data[1] instanceof PDFDocumentProxy).toEqual(true);
  54. expect(loadingTask).toEqual(data[1].loadingTask);
  55. loadingTask.destroy();
  56. done();
  57. }).catch(function (reason) {
  58. done.fail(reason);
  59. });
  60. });
  61. it('creates pdf doc from URL and aborts before worker initialized', function (done) {
  62. var loadingTask = PDFJS.getDocument(basicApiUrl);
  63. loadingTask.destroy();
  64. loadingTask.promise.then(function (reason) {
  65. done.fail('shall fail loading');
  66. }).catch(function (reason) {
  67. expect(true).toEqual(true);
  68. done();
  69. });
  70. });
  71. it('creates pdf doc from URL and aborts loading after worker initialized', function (done) {
  72. var loadingTask = PDFJS.getDocument(basicApiUrl);
  73. var destroyed = loadingTask._worker.promise.then(function () {
  74. return loadingTask.destroy();
  75. });
  76. destroyed.then(function (data) {
  77. expect(true).toEqual(true);
  78. done();
  79. }).catch(function (reason) {
  80. done.fail(reason);
  81. });
  82. });
  83. it('creates pdf doc from typed array', function (done) {
  84. var nonBinaryRequest = PDFJS.disableWorker;
  85. var request = new XMLHttpRequest();
  86. request.open('GET', basicApiUrl, false);
  87. if (!nonBinaryRequest) {
  88. try {
  89. request.responseType = 'arraybuffer';
  90. nonBinaryRequest = request.responseType !== 'arraybuffer';
  91. } catch (e) {
  92. nonBinaryRequest = true;
  93. }
  94. }
  95. if (nonBinaryRequest && request.overrideMimeType) {
  96. request.overrideMimeType('text/plain; charset=x-user-defined');
  97. }
  98. request.send(null);
  99. var typedArrayPdf;
  100. if (nonBinaryRequest) {
  101. var data = Array.prototype.map.call(request.responseText, function (ch) {
  102. return ch.charCodeAt(0) & 0xFF;
  103. });
  104. typedArrayPdf = new Uint8Array(data);
  105. } else {
  106. typedArrayPdf = new Uint8Array(request.response);
  107. }
  108. expect(typedArrayPdf.length).toEqual(basicApiFileLength);
  109. var loadingTask = PDFJS.getDocument(typedArrayPdf);
  110. loadingTask.promise.then(function (data) {
  111. expect(data instanceof PDFDocumentProxy).toEqual(true);
  112. loadingTask.destroy();
  113. done();
  114. }).catch(function (reason) {
  115. done.fail(reason);
  116. });
  117. });
  118. it('creates pdf doc from invalid PDF file', function (done) {
  119. var url = new URL('../pdfs/bug1020226.pdf', window.location).href;
  120. var loadingTask = PDFJS.getDocument(url);
  121. loadingTask.promise.then(function () {
  122. done.fail('shall fail loading');
  123. }).catch(function (error) {
  124. expect(error instanceof InvalidPDFException).toEqual(true);
  125. loadingTask.destroy();
  126. done();
  127. });
  128. });
  129. it('creates pdf doc from non-existent URL', function (done) {
  130. var nonExistentUrl = new URL('../pdfs/non-existent.pdf', window.location).href;
  131. var loadingTask = PDFJS.getDocument(nonExistentUrl);
  132. loadingTask.promise.then(function (error) {
  133. done.fail('shall fail loading');
  134. }).catch(function (error) {
  135. expect(error instanceof MissingPDFException).toEqual(true);
  136. loadingTask.destroy();
  137. done();
  138. });
  139. });
  140. it('creates pdf doc from PDF file protected with user and owner password', function (done) {
  141. var url = new URL('../pdfs/pr6531_1.pdf', window.location).href;
  142. var loadingTask = PDFJS.getDocument(url);
  143. var isPasswordNeededResolved = false;
  144. var passwordNeededCapability = createPromiseCapability();
  145. var isPasswordIncorrectResolved = false;
  146. var passwordIncorrectCapability = createPromiseCapability();
  147. loadingTask.onPassword = function (updatePassword, reason) {
  148. if (reason === PasswordResponses.NEED_PASSWORD && !isPasswordNeededResolved) {
  149. isPasswordNeededResolved = true;
  150. passwordNeededCapability.resolve();
  151. updatePassword('qwerty');
  152. return;
  153. }
  154. if (reason === PasswordResponses.INCORRECT_PASSWORD && !isPasswordIncorrectResolved) {
  155. isPasswordIncorrectResolved = true;
  156. passwordIncorrectCapability.resolve();
  157. updatePassword('asdfasdf');
  158. return;
  159. }
  160. expect(false).toEqual(true);
  161. };
  162. var promises = [passwordNeededCapability.promise, passwordIncorrectCapability.promise, loadingTask.promise];
  163. Promise.all(promises).then(function (data) {
  164. expect(data[2] instanceof PDFDocumentProxy).toEqual(true);
  165. loadingTask.destroy();
  166. done();
  167. }).catch(function (reason) {
  168. done.fail(reason);
  169. });
  170. });
  171. it('creates pdf doc from PDF file protected with only a user password', function (done) {
  172. var url = new URL('../pdfs/pr6531_2.pdf', window.location).href;
  173. var passwordNeededLoadingTask = PDFJS.getDocument({
  174. url: url,
  175. password: ''
  176. });
  177. var result1 = passwordNeededLoadingTask.promise.then(function () {
  178. done.fail('shall fail with no password');
  179. return Promise.reject(new Error('loadingTask should be rejected'));
  180. }, function (data) {
  181. expect(data instanceof PasswordException).toEqual(true);
  182. expect(data.code).toEqual(PasswordResponses.NEED_PASSWORD);
  183. return passwordNeededLoadingTask.destroy();
  184. });
  185. var passwordIncorrectLoadingTask = PDFJS.getDocument({
  186. url: url,
  187. password: 'qwerty'
  188. });
  189. var result2 = passwordIncorrectLoadingTask.promise.then(function () {
  190. done.fail('shall fail with wrong password');
  191. return Promise.reject(new Error('loadingTask should be rejected'));
  192. }, function (data) {
  193. expect(data instanceof PasswordException).toEqual(true);
  194. expect(data.code).toEqual(PasswordResponses.INCORRECT_PASSWORD);
  195. return passwordIncorrectLoadingTask.destroy();
  196. });
  197. var passwordAcceptedLoadingTask = PDFJS.getDocument({
  198. url: url,
  199. password: 'asdfasdf'
  200. });
  201. var result3 = passwordAcceptedLoadingTask.promise.then(function (data) {
  202. expect(data instanceof PDFDocumentProxy).toEqual(true);
  203. return passwordAcceptedLoadingTask.destroy();
  204. });
  205. Promise.all([result1, result2, result3]).then(function () {
  206. done();
  207. }).catch(function (reason) {
  208. done.fail(reason);
  209. });
  210. });
  211. it('creates pdf doc from password protected PDF file and aborts/throws ' + 'in the onPassword callback (issue 7806)', function (done) {
  212. var url = new URL('../pdfs/issue3371.pdf', window.location).href;
  213. var passwordNeededLoadingTask = PDFJS.getDocument(url);
  214. var passwordIncorrectLoadingTask = PDFJS.getDocument({
  215. url: url,
  216. password: 'qwerty'
  217. });
  218. passwordNeededLoadingTask.onPassword = function (callback, reason) {
  219. if (reason === PasswordResponses.NEED_PASSWORD) {
  220. passwordNeededLoadingTask.destroy();
  221. return;
  222. }
  223. expect(false).toEqual(true);
  224. };
  225. var result1 = passwordNeededLoadingTask.promise.then(function () {
  226. done.fail('shall fail since the loadingTask should be destroyed');
  227. return Promise.reject(new Error('loadingTask should be rejected'));
  228. }, function (reason) {
  229. expect(reason instanceof PasswordException).toEqual(true);
  230. expect(reason.code).toEqual(PasswordResponses.NEED_PASSWORD);
  231. });
  232. passwordIncorrectLoadingTask.onPassword = function (callback, reason) {
  233. if (reason === PasswordResponses.INCORRECT_PASSWORD) {
  234. throw new Error('Incorrect password');
  235. }
  236. expect(false).toEqual(true);
  237. };
  238. var result2 = passwordIncorrectLoadingTask.promise.then(function () {
  239. done.fail('shall fail since the onPassword callback should throw');
  240. return Promise.reject(new Error('loadingTask should be rejected'));
  241. }, function (reason) {
  242. expect(reason instanceof PasswordException).toEqual(true);
  243. expect(reason.code).toEqual(PasswordResponses.INCORRECT_PASSWORD);
  244. return passwordIncorrectLoadingTask.destroy();
  245. });
  246. Promise.all([result1, result2]).then(function () {
  247. done();
  248. }).catch(function (reason) {
  249. done.fail(reason);
  250. });
  251. });
  252. });
  253. });
  254. describe('PDFWorker', function () {
  255. it('worker created or destroyed', function (done) {
  256. var worker = new PDFJS.PDFWorker('test1');
  257. worker.promise.then(function () {
  258. expect(worker.name).toEqual('test1');
  259. expect(!!worker.port).toEqual(true);
  260. expect(worker.destroyed).toEqual(false);
  261. expect(!!worker._webWorker).toEqual(true);
  262. expect(worker.port === worker._webWorker).toEqual(true);
  263. worker.destroy();
  264. expect(!!worker.port).toEqual(false);
  265. expect(worker.destroyed).toEqual(true);
  266. done();
  267. }).catch(function (reason) {
  268. done.fail(reason);
  269. });
  270. });
  271. it('worker created or destroyed by getDocument', function (done) {
  272. var loadingTask = PDFJS.getDocument(basicApiUrl);
  273. var worker;
  274. loadingTask.promise.then(function () {
  275. worker = loadingTask._worker;
  276. expect(!!worker).toEqual(true);
  277. });
  278. var destroyPromise = loadingTask.promise.then(function () {
  279. return loadingTask.destroy();
  280. });
  281. destroyPromise.then(function () {
  282. var destroyedWorker = loadingTask._worker;
  283. expect(!!destroyedWorker).toEqual(false);
  284. expect(worker.destroyed).toEqual(true);
  285. done();
  286. }).catch(function (reason) {
  287. done.fail(reason);
  288. });
  289. });
  290. it('worker created and can be used in getDocument', function (done) {
  291. var worker = new PDFJS.PDFWorker('test1');
  292. var loadingTask = PDFJS.getDocument({
  293. url: basicApiUrl,
  294. worker: worker
  295. });
  296. loadingTask.promise.then(function () {
  297. var docWorker = loadingTask._worker;
  298. expect(!!docWorker).toEqual(false);
  299. var messageHandlerPort = loadingTask._transport.messageHandler.comObj;
  300. expect(messageHandlerPort === worker.port).toEqual(true);
  301. });
  302. var destroyPromise = loadingTask.promise.then(function () {
  303. return loadingTask.destroy();
  304. });
  305. destroyPromise.then(function () {
  306. expect(worker.destroyed).toEqual(false);
  307. worker.destroy();
  308. done();
  309. }).catch(function (reason) {
  310. done.fail(reason);
  311. });
  312. });
  313. it('creates more than one worker', function (done) {
  314. var worker1 = new PDFJS.PDFWorker('test1');
  315. var worker2 = new PDFJS.PDFWorker('test2');
  316. var worker3 = new PDFJS.PDFWorker('test3');
  317. var ready = Promise.all([worker1.promise, worker2.promise, worker3.promise]);
  318. ready.then(function () {
  319. expect(worker1.port !== worker2.port && worker1.port !== worker3.port && worker2.port !== worker3.port).toEqual(true);
  320. worker1.destroy();
  321. worker2.destroy();
  322. worker3.destroy();
  323. done();
  324. }).catch(function (reason) {
  325. done.fail(reason);
  326. });
  327. });
  328. });
  329. describe('PDFDocument', function () {
  330. var loadingTask;
  331. var doc;
  332. beforeAll(function (done) {
  333. loadingTask = PDFJS.getDocument(basicApiUrl);
  334. loadingTask.promise.then(function (data) {
  335. doc = data;
  336. done();
  337. });
  338. });
  339. afterAll(function () {
  340. loadingTask.destroy();
  341. });
  342. it('gets number of pages', function () {
  343. expect(doc.numPages).toEqual(3);
  344. });
  345. it('gets fingerprint', function () {
  346. var fingerprint = doc.fingerprint;
  347. expect(typeof fingerprint).toEqual('string');
  348. expect(fingerprint.length > 0).toEqual(true);
  349. });
  350. it('gets page', function (done) {
  351. var promise = doc.getPage(1);
  352. promise.then(function (data) {
  353. expect(data instanceof PDFPageProxy).toEqual(true);
  354. expect(data.pageIndex).toEqual(0);
  355. done();
  356. }).catch(function (reason) {
  357. done.fail(reason);
  358. });
  359. });
  360. it('gets non-existent page', function (done) {
  361. var outOfRangePromise = doc.getPage(100);
  362. var nonIntegerPromise = doc.getPage(2.5);
  363. var nonNumberPromise = doc.getPage('1');
  364. outOfRangePromise = outOfRangePromise.then(function () {
  365. throw new Error('shall fail for out-of-range pageNumber parameter');
  366. }, function (reason) {
  367. expect(reason instanceof Error).toEqual(true);
  368. });
  369. nonIntegerPromise = nonIntegerPromise.then(function () {
  370. throw new Error('shall fail for non-integer pageNumber parameter');
  371. }, function (reason) {
  372. expect(reason instanceof Error).toEqual(true);
  373. });
  374. nonNumberPromise = nonNumberPromise.then(function () {
  375. throw new Error('shall fail for non-number pageNumber parameter');
  376. }, function (reason) {
  377. expect(reason instanceof Error).toEqual(true);
  378. });
  379. Promise.all([outOfRangePromise, nonIntegerPromise, nonNumberPromise]).then(function () {
  380. done();
  381. }).catch(function (reason) {
  382. done.fail(reason);
  383. });
  384. });
  385. it('gets page index', function (done) {
  386. var ref = {
  387. num: 17,
  388. gen: 0
  389. };
  390. var promise = doc.getPageIndex(ref);
  391. promise.then(function (pageIndex) {
  392. expect(pageIndex).toEqual(1);
  393. done();
  394. }).catch(function (reason) {
  395. done.fail(reason);
  396. });
  397. });
  398. it('gets invalid page index', function (done) {
  399. var ref = {
  400. num: 3,
  401. gen: 0
  402. };
  403. var promise = doc.getPageIndex(ref);
  404. promise.then(function () {
  405. done.fail('shall fail for invalid page reference.');
  406. }).catch(function (reason) {
  407. expect(reason instanceof Error).toEqual(true);
  408. done();
  409. });
  410. });
  411. it('gets destinations, from /Dests dictionary', function (done) {
  412. var promise = doc.getDestinations();
  413. promise.then(function (data) {
  414. expect(data).toEqual({
  415. chapter1: [{
  416. gen: 0,
  417. num: 17
  418. }, { name: 'XYZ' }, 0, 841.89, null]
  419. });
  420. done();
  421. }).catch(function (reason) {
  422. done.fail(reason);
  423. });
  424. });
  425. it('gets a destination, from /Dests dictionary', function (done) {
  426. var promise = doc.getDestination('chapter1');
  427. promise.then(function (data) {
  428. expect(data).toEqual([{
  429. gen: 0,
  430. num: 17
  431. }, { name: 'XYZ' }, 0, 841.89, null]);
  432. done();
  433. }).catch(function (reason) {
  434. done.fail(reason);
  435. });
  436. });
  437. it('gets a non-existent destination, from /Dests dictionary', function (done) {
  438. var promise = doc.getDestination('non-existent-named-destination');
  439. promise.then(function (data) {
  440. expect(data).toEqual(null);
  441. done();
  442. }).catch(function (reason) {
  443. done.fail(reason);
  444. });
  445. });
  446. it('gets destinations, from /Names (NameTree) dictionary', function (done) {
  447. var url = new URL('../pdfs/issue6204.pdf', window.location).href;
  448. var loadingTask = PDFJS.getDocument(url);
  449. var promise = loadingTask.promise.then(function (pdfDocument) {
  450. return pdfDocument.getDestinations();
  451. });
  452. promise.then(function (destinations) {
  453. expect(destinations).toEqual({
  454. 'Page.1': [{
  455. num: 1,
  456. gen: 0
  457. }, { name: 'XYZ' }, 0, 375, null],
  458. 'Page.2': [{
  459. num: 6,
  460. gen: 0
  461. }, { name: 'XYZ' }, 0, 375, null]
  462. });
  463. loadingTask.destroy();
  464. done();
  465. }).catch(function (reason) {
  466. done.fail(reason);
  467. });
  468. });
  469. it('gets a destination, from /Names (NameTree) dictionary', function (done) {
  470. var url = new URL('../pdfs/issue6204.pdf', window.location).href;
  471. var loadingTask = PDFJS.getDocument(url);
  472. var promise = loadingTask.promise.then(function (pdfDocument) {
  473. return pdfDocument.getDestination('Page.1');
  474. });
  475. promise.then(function (destination) {
  476. expect(destination).toEqual([{
  477. num: 1,
  478. gen: 0
  479. }, { name: 'XYZ' }, 0, 375, null]);
  480. loadingTask.destroy();
  481. done();
  482. }).catch(function (reason) {
  483. done.fail(reason);
  484. });
  485. });
  486. it('gets a non-existent destination, from /Names (NameTree) dictionary', function (done) {
  487. var url = new URL('../pdfs/issue6204.pdf', window.location).href;
  488. var loadingTask = PDFJS.getDocument(url);
  489. var promise = loadingTask.promise.then(function (pdfDocument) {
  490. return pdfDocument.getDestination('non-existent-named-destination');
  491. });
  492. promise.then(function (destination) {
  493. expect(destination).toEqual(null);
  494. loadingTask.destroy();
  495. done();
  496. }).catch(function (reason) {
  497. done.fail(reason);
  498. });
  499. });
  500. it('gets non-existent page labels', function (done) {
  501. var promise = doc.getPageLabels();
  502. promise.then(function (data) {
  503. expect(data).toEqual(null);
  504. done();
  505. }).catch(function (reason) {
  506. done.fail(reason);
  507. });
  508. });
  509. it('gets page labels', function (done) {
  510. var url0 = new URL('../pdfs/bug793632.pdf', window.location).href;
  511. var loadingTask0 = PDFJS.getDocument(url0);
  512. var promise0 = loadingTask0.promise.then(function (pdfDoc) {
  513. return pdfDoc.getPageLabels();
  514. });
  515. var url1 = new URL('../pdfs/issue1453.pdf', window.location).href;
  516. var loadingTask1 = PDFJS.getDocument(url1);
  517. var promise1 = loadingTask1.promise.then(function (pdfDoc) {
  518. return pdfDoc.getPageLabels();
  519. });
  520. var url2 = new URL('../pdfs/rotation.pdf', window.location).href;
  521. var loadingTask2 = PDFJS.getDocument(url2);
  522. var promise2 = loadingTask2.promise.then(function (pdfDoc) {
  523. return pdfDoc.getPageLabels();
  524. });
  525. var url3 = new URL('../pdfs/bad-PageLabels.pdf', window.location).href;
  526. var loadingTask3 = PDFJS.getDocument(url3);
  527. var promise3 = loadingTask3.promise.then(function (pdfDoc) {
  528. return pdfDoc.getPageLabels();
  529. });
  530. Promise.all([promise0, promise1, promise2, promise3]).then(function (pageLabels) {
  531. expect(pageLabels[0]).toEqual(['i', 'ii', 'iii', '1']);
  532. expect(pageLabels[1]).toEqual(['Front Page1']);
  533. expect(pageLabels[2]).toEqual(['1', '2']);
  534. expect(pageLabels[3]).toEqual(['X3']);
  535. loadingTask0.destroy();
  536. loadingTask1.destroy();
  537. loadingTask2.destroy();
  538. loadingTask3.destroy();
  539. done();
  540. }).catch(function (reason) {
  541. done.fail(reason);
  542. });
  543. });
  544. it('gets non-existent attachments', function (done) {
  545. var promise = doc.getAttachments();
  546. promise.then(function (data) {
  547. expect(data).toEqual(null);
  548. done();
  549. }).catch(function (reason) {
  550. done.fail(reason);
  551. });
  552. });
  553. it('gets attachments', function (done) {
  554. var url = new URL('../pdfs/bug766138.pdf', window.location).href;
  555. var loadingTask = PDFJS.getDocument(url);
  556. var promise = loadingTask.promise.then(function (pdfDoc) {
  557. return pdfDoc.getAttachments();
  558. });
  559. promise.then(function (data) {
  560. var attachment = data['Press Quality.joboptions'];
  561. expect(attachment.filename).toEqual('Press Quality.joboptions');
  562. expect(attachment.content instanceof Uint8Array).toBeTruthy();
  563. expect(attachment.content.length).toEqual(30098);
  564. loadingTask.destroy();
  565. done();
  566. }).catch(function (reason) {
  567. done.fail(reason);
  568. });
  569. });
  570. it('gets javascript', function (done) {
  571. var promise = doc.getJavaScript();
  572. promise.then(function (data) {
  573. expect(data).toEqual([]);
  574. done();
  575. }).catch(function (reason) {
  576. done.fail(reason);
  577. });
  578. });
  579. var viewerPrintRegExp = /\bprint\s*\(/;
  580. it('gets javascript with printing instructions (Print action)', function (done) {
  581. var pdfUrl = new URL('../pdfs/bug1001080.pdf', window.location).href;
  582. var loadingTask = PDFJS.getDocument(pdfUrl);
  583. var promise = loadingTask.promise.then(function (doc) {
  584. return doc.getJavaScript();
  585. });
  586. promise.then(function (data) {
  587. expect(data).toEqual(['print({});']);
  588. expect(data[0]).toMatch(viewerPrintRegExp);
  589. loadingTask.destroy();
  590. done();
  591. }).catch(function (reason) {
  592. done.fail(reason);
  593. });
  594. });
  595. it('gets javascript with printing instructions (JS action)', function (done) {
  596. var pdfUrl = new URL('../pdfs/issue6106.pdf', window.location).href;
  597. var loadingTask = PDFJS.getDocument(pdfUrl);
  598. var promise = loadingTask.promise.then(function (doc) {
  599. return doc.getJavaScript();
  600. });
  601. promise.then(function (data) {
  602. expect(data).toEqual(['this.print({bUI:true,bSilent:false,bShrinkToFit:true});']);
  603. expect(data[0]).toMatch(viewerPrintRegExp);
  604. loadingTask.destroy();
  605. done();
  606. }).catch(function (reason) {
  607. done.fail(reason);
  608. });
  609. });
  610. it('gets non-existent outline', function (done) {
  611. var url = new URL('../pdfs/tracemonkey.pdf', window.location).href;
  612. var loadingTask = PDFJS.getDocument(url);
  613. var promise = loadingTask.promise.then(function (pdfDocument) {
  614. return pdfDocument.getOutline();
  615. });
  616. promise.then(function (outline) {
  617. expect(outline).toEqual(null);
  618. loadingTask.destroy();
  619. done();
  620. }).catch(function (reason) {
  621. done.fail(reason);
  622. });
  623. });
  624. it('gets outline', function (done) {
  625. var promise = doc.getOutline();
  626. promise.then(function (outline) {
  627. expect(outline instanceof Array).toEqual(true);
  628. expect(outline.length).toEqual(2);
  629. var outlineItem = outline[1];
  630. expect(outlineItem.title).toEqual('Chapter 1');
  631. expect(outlineItem.dest instanceof Array).toEqual(true);
  632. expect(outlineItem.url).toEqual(null);
  633. expect(outlineItem.unsafeUrl).toBeUndefined();
  634. expect(outlineItem.newWindow).toBeUndefined();
  635. expect(outlineItem.bold).toEqual(true);
  636. expect(outlineItem.italic).toEqual(false);
  637. expect(outlineItem.color).toEqual(new Uint8Array([0, 64, 128]));
  638. expect(outlineItem.items.length).toEqual(1);
  639. expect(outlineItem.items[0].title).toEqual('Paragraph 1.1');
  640. done();
  641. }).catch(function (reason) {
  642. done.fail(reason);
  643. });
  644. });
  645. it('gets outline containing a url', function (done) {
  646. var pdfUrl = new URL('../pdfs/issue3214.pdf', window.location).href;
  647. var loadingTask = PDFJS.getDocument(pdfUrl);
  648. loadingTask.promise.then(function (pdfDocument) {
  649. pdfDocument.getOutline().then(function (outline) {
  650. expect(outline instanceof Array).toEqual(true);
  651. expect(outline.length).toEqual(5);
  652. var outlineItemTwo = outline[2];
  653. expect(typeof outlineItemTwo.title).toEqual('string');
  654. expect(outlineItemTwo.dest).toEqual(null);
  655. expect(outlineItemTwo.url).toEqual('http://google.com/');
  656. expect(outlineItemTwo.unsafeUrl).toEqual('http://google.com');
  657. expect(outlineItemTwo.newWindow).toBeUndefined();
  658. var outlineItemOne = outline[1];
  659. expect(outlineItemOne.bold).toEqual(false);
  660. expect(outlineItemOne.italic).toEqual(true);
  661. expect(outlineItemOne.color).toEqual(new Uint8Array([0, 0, 0]));
  662. loadingTask.destroy();
  663. done();
  664. });
  665. }).catch(function (reason) {
  666. done.fail(reason);
  667. });
  668. });
  669. it('gets metadata', function (done) {
  670. var promise = doc.getMetadata();
  671. promise.then(function (metadata) {
  672. expect(metadata.info['Title']).toEqual('Basic API Test');
  673. expect(metadata.info['PDFFormatVersion']).toEqual('1.7');
  674. expect(metadata.metadata.get('dc:title')).toEqual('Basic API Test');
  675. done();
  676. }).catch(function (reason) {
  677. done.fail(reason);
  678. });
  679. });
  680. it('gets data', function (done) {
  681. var promise = doc.getData();
  682. promise.then(function (data) {
  683. expect(data instanceof Uint8Array).toEqual(true);
  684. expect(data.length).toEqual(basicApiFileLength);
  685. done();
  686. }).catch(function (reason) {
  687. done.fail(reason);
  688. });
  689. });
  690. it('gets download info', function (done) {
  691. var promise = doc.getDownloadInfo();
  692. promise.then(function (data) {
  693. expect(data).toEqual({ length: basicApiFileLength });
  694. done();
  695. }).catch(function (reason) {
  696. done.fail(reason);
  697. });
  698. });
  699. it('gets stats', function (done) {
  700. var promise = doc.getStats();
  701. promise.then(function (stats) {
  702. expect(stats).toEqual({
  703. streamTypes: [],
  704. fontTypes: []
  705. });
  706. done();
  707. }).catch(function (reason) {
  708. done.fail(reason);
  709. });
  710. });
  711. it('checks that fingerprints are unique', function (done) {
  712. var url1 = new URL('../pdfs/issue4436r.pdf', window.location).href;
  713. var loadingTask1 = PDFJS.getDocument(url1);
  714. var url2 = new URL('../pdfs/issue4575.pdf', window.location).href;
  715. var loadingTask2 = PDFJS.getDocument(url2);
  716. var promises = [loadingTask1.promise, loadingTask2.promise];
  717. Promise.all(promises).then(function (data) {
  718. var fingerprint1 = data[0].fingerprint;
  719. expect(typeof fingerprint1).toEqual('string');
  720. expect(fingerprint1.length > 0).toEqual(true);
  721. var fingerprint2 = data[1].fingerprint;
  722. expect(typeof fingerprint2).toEqual('string');
  723. expect(fingerprint2.length > 0).toEqual(true);
  724. expect(fingerprint1).not.toEqual(fingerprint2);
  725. loadingTask1.destroy();
  726. loadingTask2.destroy();
  727. done();
  728. }).catch(function (reason) {
  729. done.fail(reason);
  730. });
  731. });
  732. });
  733. describe('Page', function () {
  734. var loadingTask;
  735. var pdfDocument, page;
  736. beforeAll(function (done) {
  737. loadingTask = PDFJS.getDocument(basicApiUrl);
  738. loadingTask.promise.then(function (doc) {
  739. pdfDocument = doc;
  740. pdfDocument.getPage(1).then(function (data) {
  741. page = data;
  742. done();
  743. });
  744. }).catch(function (reason) {
  745. done.fail(reason);
  746. });
  747. });
  748. afterAll(function () {
  749. loadingTask.destroy();
  750. });
  751. it('gets page number', function () {
  752. expect(page.pageNumber).toEqual(1);
  753. });
  754. it('gets rotate', function () {
  755. expect(page.rotate).toEqual(0);
  756. });
  757. it('gets ref', function () {
  758. expect(page.ref).toEqual({
  759. num: 15,
  760. gen: 0
  761. });
  762. });
  763. it('gets userUnit', function () {
  764. expect(page.userUnit).toEqual(1.0);
  765. });
  766. it('gets view', function () {
  767. expect(page.view).toEqual([0, 0, 595.28, 841.89]);
  768. });
  769. it('gets viewport', function () {
  770. var viewport = page.getViewport(1.5, 90);
  771. expect(viewport.viewBox).toEqual(page.view);
  772. expect(viewport.scale).toEqual(1.5);
  773. expect(viewport.rotation).toEqual(90);
  774. expect(viewport.transform).toEqual([0, 1.5, 1.5, 0, 0, 0]);
  775. expect(viewport.width).toEqual(1262.835);
  776. expect(viewport.height).toEqual(892.92);
  777. });
  778. it('gets annotations', function (done) {
  779. var defaultPromise = page.getAnnotations().then(function (data) {
  780. expect(data.length).toEqual(4);
  781. });
  782. var displayPromise = page.getAnnotations({ intent: 'display' }).then(function (data) {
  783. expect(data.length).toEqual(4);
  784. });
  785. var printPromise = page.getAnnotations({ intent: 'print' }).then(function (data) {
  786. expect(data.length).toEqual(4);
  787. });
  788. Promise.all([defaultPromise, displayPromise, printPromise]).then(function () {
  789. done();
  790. }).catch(function (reason) {
  791. done.fail(reason);
  792. });
  793. });
  794. it('gets annotations containing relative URLs (bug 766086)', function (done) {
  795. var url = new URL('../pdfs/bug766086.pdf', window.location).href;
  796. var defaultLoadingTask = PDFJS.getDocument(url);
  797. var defaultPromise = defaultLoadingTask.promise.then(function (pdfDoc) {
  798. return pdfDoc.getPage(1).then(function (pdfPage) {
  799. return pdfPage.getAnnotations();
  800. });
  801. });
  802. var docBaseUrlLoadingTask = PDFJS.getDocument({
  803. url: url,
  804. docBaseUrl: 'http://www.example.com/test/pdfs/qwerty.pdf'
  805. });
  806. var docBaseUrlPromise = docBaseUrlLoadingTask.promise.then(function (pdfDoc) {
  807. return pdfDoc.getPage(1).then(function (pdfPage) {
  808. return pdfPage.getAnnotations();
  809. });
  810. });
  811. var invalidDocBaseUrlLoadingTask = PDFJS.getDocument({
  812. url: url,
  813. docBaseUrl: 'qwerty.pdf'
  814. });
  815. var invalidDocBaseUrlPromise = invalidDocBaseUrlLoadingTask.promise.then(function (pdfDoc) {
  816. return pdfDoc.getPage(1).then(function (pdfPage) {
  817. return pdfPage.getAnnotations();
  818. });
  819. });
  820. Promise.all([defaultPromise, docBaseUrlPromise, invalidDocBaseUrlPromise]).then(function (data) {
  821. var defaultAnnotations = data[0];
  822. var docBaseUrlAnnotations = data[1];
  823. var invalidDocBaseUrlAnnotations = data[2];
  824. expect(defaultAnnotations[0].url).toBeUndefined();
  825. expect(defaultAnnotations[0].unsafeUrl).toEqual('../../0021/002156/215675E.pdf#nameddest=15');
  826. expect(docBaseUrlAnnotations[0].url).toEqual('http://www.example.com/0021/002156/215675E.pdf#nameddest=15');
  827. expect(docBaseUrlAnnotations[0].unsafeUrl).toEqual('../../0021/002156/215675E.pdf#nameddest=15');
  828. expect(invalidDocBaseUrlAnnotations[0].url).toBeUndefined();
  829. expect(invalidDocBaseUrlAnnotations[0].unsafeUrl).toEqual('../../0021/002156/215675E.pdf#nameddest=15');
  830. defaultLoadingTask.destroy();
  831. docBaseUrlLoadingTask.destroy();
  832. invalidDocBaseUrlLoadingTask.destroy();
  833. done();
  834. }).catch(function (reason) {
  835. done.fail(reason);
  836. });
  837. });
  838. it('gets text content', function (done) {
  839. var defaultPromise = page.getTextContent();
  840. var parametersPromise = page.getTextContent({
  841. normalizeWhitespace: true,
  842. disableCombineTextItems: true
  843. });
  844. var promises = [defaultPromise, parametersPromise];
  845. Promise.all(promises).then(function (data) {
  846. expect(!!data[0].items).toEqual(true);
  847. expect(data[0].items.length).toEqual(7);
  848. expect(!!data[0].styles).toEqual(true);
  849. expect(JSON.stringify(data[0])).toEqual(JSON.stringify(data[1]));
  850. done();
  851. }).catch(function (reason) {
  852. done.fail(reason);
  853. });
  854. });
  855. it('gets operator list', function (done) {
  856. var promise = page.getOperatorList();
  857. promise.then(function (oplist) {
  858. expect(!!oplist.fnArray).toEqual(true);
  859. expect(!!oplist.argsArray).toEqual(true);
  860. expect(oplist.lastChunk).toEqual(true);
  861. done();
  862. }).catch(function (reason) {
  863. done.fail(reason);
  864. });
  865. });
  866. it('gets stats after parsing page', function (done) {
  867. var promise = page.getOperatorList().then(function () {
  868. return pdfDocument.getStats();
  869. });
  870. var expectedStreamTypes = [];
  871. expectedStreamTypes[StreamType.FLATE] = true;
  872. var expectedFontTypes = [];
  873. expectedFontTypes[FontType.TYPE1] = true;
  874. expectedFontTypes[FontType.CIDFONTTYPE2] = true;
  875. promise.then(function (stats) {
  876. expect(stats).toEqual({
  877. streamTypes: expectedStreamTypes,
  878. fontTypes: expectedFontTypes
  879. });
  880. done();
  881. }).catch(function (reason) {
  882. done.fail(reason);
  883. });
  884. });
  885. });
  886. describe('Multiple PDFJS instances', function () {
  887. var pdf1 = new URL('../pdfs/tracemonkey.pdf', window.location).href;
  888. var pdf2 = new URL('../pdfs/TAMReview.pdf', window.location).href;
  889. var pdf3 = new URL('../pdfs/issue6068.pdf', window.location).href;
  890. var loadingTasks = [];
  891. var pdfDocuments = [];
  892. function renderPDF(filename) {
  893. var loadingTask = PDFJS.getDocument(filename);
  894. loadingTasks.push(loadingTask);
  895. return loadingTask.promise.then(function (pdf) {
  896. pdfDocuments.push(pdf);
  897. return pdf.getPage(1);
  898. }).then(function (page) {
  899. var c = document.createElement('canvas');
  900. var v = page.getViewport(1.2);
  901. c.width = v.width;
  902. c.height = v.height;
  903. return page.render({
  904. canvasContext: c.getContext('2d'),
  905. viewport: v
  906. }).then(function () {
  907. return c.toDataURL();
  908. });
  909. });
  910. }
  911. afterEach(function (done) {
  912. var destroyPromises = pdfDocuments.map(function (pdfDocument) {
  913. return pdfDocument.destroy();
  914. });
  915. var destroyPromises2 = loadingTasks.map(function (loadingTask) {
  916. return loadingTask.destroy();
  917. });
  918. Promise.all(destroyPromises.concat(destroyPromises2)).then(function () {
  919. done();
  920. });
  921. });
  922. it('should correctly render PDFs in parallel', function (done) {
  923. var baseline1, baseline2, baseline3;
  924. var promiseDone = renderPDF(pdf1).then(function (data1) {
  925. baseline1 = data1;
  926. return renderPDF(pdf2);
  927. }).then(function (data2) {
  928. baseline2 = data2;
  929. return renderPDF(pdf3);
  930. }).then(function (data3) {
  931. baseline3 = data3;
  932. return Promise.all([renderPDF(pdf1), renderPDF(pdf2), renderPDF(pdf3)]);
  933. }).then(function (dataUrls) {
  934. expect(dataUrls[0]).toEqual(baseline1);
  935. expect(dataUrls[1]).toEqual(baseline2);
  936. expect(dataUrls[2]).toEqual(baseline3);
  937. return true;
  938. });
  939. promiseDone.then(function () {
  940. done();
  941. }).catch(function (reason) {
  942. done.fail(reason);
  943. });
  944. });
  945. });
  946. describe('PDFDataRangeTransport', function () {
  947. var pdfPath = new URL('../pdfs/tracemonkey.pdf', window.location).href;
  948. var loadPromise;
  949. function getDocumentData() {
  950. if (loadPromise) {
  951. return loadPromise;
  952. }
  953. loadPromise = new Promise(function (resolve, reject) {
  954. var xhr = new XMLHttpRequest(pdfPath);
  955. xhr.open('GET', pdfPath);
  956. xhr.responseType = 'arraybuffer';
  957. xhr.onload = function () {
  958. resolve(new Uint8Array(xhr.response));
  959. };
  960. xhr.onerror = function () {
  961. reject(new Error('PDF is not loaded'));
  962. };
  963. xhr.send();
  964. });
  965. return loadPromise;
  966. }
  967. it('should fetch document info and page using ranges', function (done) {
  968. var transport;
  969. var initialDataLength = 4000;
  970. var fetches = 0;
  971. var getDocumentPromise = getDocumentData().then(function (data) {
  972. var initialData = data.subarray(0, initialDataLength);
  973. transport = new PDFJS.PDFDataRangeTransport(data.length, initialData);
  974. transport.requestDataRange = function (begin, end) {
  975. fetches++;
  976. waitSome(function () {
  977. transport.onDataProgress(4000);
  978. transport.onDataRange(begin, data.subarray(begin, end));
  979. });
  980. };
  981. var loadingTask = PDFJS.getDocument(transport);
  982. return loadingTask.promise;
  983. });
  984. var pdfDocument;
  985. var getPagePromise = getDocumentPromise.then(function (pdfDocument_) {
  986. pdfDocument = pdfDocument_;
  987. var pagePromise = pdfDocument.getPage(10);
  988. return pagePromise;
  989. });
  990. getPagePromise.then(function (page) {
  991. expect(pdfDocument.numPages).toEqual(14);
  992. expect(page.rotate).toEqual(0);
  993. expect(fetches).toBeGreaterThan(2);
  994. done();
  995. }).catch(function (reason) {
  996. done.fail(reason);
  997. });
  998. });
  999. it('should fetch document info and page using range and streaming', function (done) {
  1000. var transport;
  1001. var initialDataLength = 4000;
  1002. var fetches = 0;
  1003. var getDocumentPromise = getDocumentData().then(function (data) {
  1004. var initialData = data.subarray(0, initialDataLength);
  1005. transport = new PDFJS.PDFDataRangeTransport(data.length, initialData);
  1006. transport.requestDataRange = function (begin, end) {
  1007. fetches++;
  1008. if (fetches === 1) {
  1009. transport.onDataProgressiveRead(data.subarray(initialDataLength));
  1010. }
  1011. waitSome(function () {
  1012. transport.onDataRange(begin, data.subarray(begin, end));
  1013. });
  1014. };
  1015. var loadingTask = PDFJS.getDocument(transport);
  1016. return loadingTask.promise;
  1017. });
  1018. var pdfDocument;
  1019. var getPagePromise = getDocumentPromise.then(function (pdfDocument_) {
  1020. pdfDocument = pdfDocument_;
  1021. var pagePromise = pdfDocument.getPage(10);
  1022. return pagePromise;
  1023. });
  1024. getPagePromise.then(function (page) {
  1025. expect(pdfDocument.numPages).toEqual(14);
  1026. expect(page.rotate).toEqual(0);
  1027. expect(fetches).toEqual(1);
  1028. done();
  1029. }).catch(function (reason) {
  1030. done.fail(reason);
  1031. });
  1032. });
  1033. });
  1034. });