base_viewer.js 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441
  1. /**
  2. * @licstart The following is the entire license notice for the
  3. * Javascript code in this page
  4. *
  5. * Copyright 2021 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. Object.defineProperty(exports, "__esModule", {
  24. value: true
  25. });
  26. exports.BaseViewer = void 0;
  27. var _pdf = require("../pdf");
  28. var _ui_utils = require("./ui_utils.js");
  29. var _pdf_rendering_queue = require("./pdf_rendering_queue.js");
  30. var _annotation_layer_builder = require("./annotation_layer_builder.js");
  31. var _l10n_utils = require("./l10n_utils.js");
  32. var _pdf_page_view = require("./pdf_page_view.js");
  33. var _pdf_link_service = require("./pdf_link_service.js");
  34. var _text_layer_builder = require("./text_layer_builder.js");
  35. var _xfa_layer_builder = require("./xfa_layer_builder.js");
  36. const DEFAULT_CACHE_SIZE = 10;
  37. function PDFPageViewBuffer(size) {
  38. const data = [];
  39. this.push = function (view) {
  40. const i = data.indexOf(view);
  41. if (i >= 0) {
  42. data.splice(i, 1);
  43. }
  44. data.push(view);
  45. if (data.length > size) {
  46. data.shift().destroy();
  47. }
  48. };
  49. this.resize = function (newSize, pagesToKeep) {
  50. size = newSize;
  51. if (pagesToKeep) {
  52. const pageIdsToKeep = new Set();
  53. for (let i = 0, iMax = pagesToKeep.length; i < iMax; ++i) {
  54. pageIdsToKeep.add(pagesToKeep[i].id);
  55. }
  56. (0, _ui_utils.moveToEndOfArray)(data, function (page) {
  57. return pageIdsToKeep.has(page.id);
  58. });
  59. }
  60. while (data.length > size) {
  61. data.shift().destroy();
  62. }
  63. };
  64. this.has = function (view) {
  65. return data.includes(view);
  66. };
  67. }
  68. function isSameScale(oldScale, newScale) {
  69. if (newScale === oldScale) {
  70. return true;
  71. }
  72. if (Math.abs(newScale - oldScale) < 1e-15) {
  73. return true;
  74. }
  75. return false;
  76. }
  77. class BaseViewer {
  78. constructor(options) {
  79. if (this.constructor === BaseViewer) {
  80. throw new Error("Cannot initialize BaseViewer.");
  81. }
  82. const viewerVersion = '2.8.335';
  83. if (_pdf.version !== viewerVersion) {
  84. throw new Error(`The API version "${_pdf.version}" does not match the Viewer version "${viewerVersion}".`);
  85. }
  86. this._name = this.constructor.name;
  87. this.container = options.container;
  88. this.viewer = options.viewer || options.container.firstElementChild;
  89. if (!(this.container?.tagName.toUpperCase() === "DIV" && this.viewer?.tagName.toUpperCase() === "DIV")) {
  90. throw new Error("Invalid `container` and/or `viewer` option.");
  91. }
  92. if (this.container.offsetParent && getComputedStyle(this.container).position !== "absolute") {
  93. throw new Error("The `container` must be absolutely positioned.");
  94. }
  95. this.eventBus = options.eventBus;
  96. this.linkService = options.linkService || new _pdf_link_service.SimpleLinkService();
  97. this.downloadManager = options.downloadManager || null;
  98. this.findController = options.findController || null;
  99. this._scriptingManager = options.scriptingManager || null;
  100. this.removePageBorders = options.removePageBorders || false;
  101. this.textLayerMode = Number.isInteger(options.textLayerMode) ? options.textLayerMode : _ui_utils.TextLayerMode.ENABLE;
  102. this.imageResourcesPath = options.imageResourcesPath || "";
  103. this.renderInteractiveForms = options.renderInteractiveForms !== false;
  104. this.enablePrintAutoRotate = options.enablePrintAutoRotate || false;
  105. this.renderer = options.renderer || _ui_utils.RendererType.CANVAS;
  106. this.enableWebGL = options.enableWebGL || false;
  107. this.useOnlyCssZoom = options.useOnlyCssZoom || false;
  108. this.maxCanvasPixels = options.maxCanvasPixels;
  109. this.l10n = options.l10n || _l10n_utils.NullL10n;
  110. this.enableScripting = options.enableScripting === true && !!this._scriptingManager;
  111. this.defaultRenderingQueue = !options.renderingQueue;
  112. if (this.defaultRenderingQueue) {
  113. this.renderingQueue = new _pdf_rendering_queue.PDFRenderingQueue();
  114. this.renderingQueue.setViewer(this);
  115. } else {
  116. this.renderingQueue = options.renderingQueue;
  117. }
  118. this.scroll = (0, _ui_utils.watchScroll)(this.container, this._scrollUpdate.bind(this));
  119. this.presentationModeState = _ui_utils.PresentationModeState.UNKNOWN;
  120. this._onBeforeDraw = this._onAfterDraw = null;
  121. this._resetView();
  122. if (this.removePageBorders) {
  123. this.viewer.classList.add("removePageBorders");
  124. }
  125. Promise.resolve().then(() => {
  126. this.eventBus.dispatch("baseviewerinit", {
  127. source: this
  128. });
  129. });
  130. }
  131. get pagesCount() {
  132. return this._pages.length;
  133. }
  134. getPageView(index) {
  135. return this._pages[index];
  136. }
  137. get pageViewsReady() {
  138. if (!this._pagesCapability.settled) {
  139. return false;
  140. }
  141. return this._pages.every(function (pageView) {
  142. return pageView?.pdfPage;
  143. });
  144. }
  145. get currentPageNumber() {
  146. return this._currentPageNumber;
  147. }
  148. set currentPageNumber(val) {
  149. if (!Number.isInteger(val)) {
  150. throw new Error("Invalid page number.");
  151. }
  152. if (!this.pdfDocument) {
  153. return;
  154. }
  155. if (!this._setCurrentPageNumber(val, true)) {
  156. console.error(`${this._name}.currentPageNumber: "${val}" is not a valid page.`);
  157. }
  158. }
  159. _setCurrentPageNumber(val, resetCurrentPageView = false) {
  160. if (this._currentPageNumber === val) {
  161. if (resetCurrentPageView) {
  162. this._resetCurrentPageView();
  163. }
  164. return true;
  165. }
  166. if (!(0 < val && val <= this.pagesCount)) {
  167. return false;
  168. }
  169. const previous = this._currentPageNumber;
  170. this._currentPageNumber = val;
  171. this.eventBus.dispatch("pagechanging", {
  172. source: this,
  173. pageNumber: val,
  174. pageLabel: this._pageLabels?.[val - 1] ?? null,
  175. previous
  176. });
  177. if (resetCurrentPageView) {
  178. this._resetCurrentPageView();
  179. }
  180. return true;
  181. }
  182. get currentPageLabel() {
  183. return this._pageLabels?.[this._currentPageNumber - 1] ?? null;
  184. }
  185. set currentPageLabel(val) {
  186. if (!this.pdfDocument) {
  187. return;
  188. }
  189. let page = val | 0;
  190. if (this._pageLabels) {
  191. const i = this._pageLabels.indexOf(val);
  192. if (i >= 0) {
  193. page = i + 1;
  194. }
  195. }
  196. if (!this._setCurrentPageNumber(page, true)) {
  197. console.error(`${this._name}.currentPageLabel: "${val}" is not a valid page.`);
  198. }
  199. }
  200. get currentScale() {
  201. return this._currentScale !== _ui_utils.UNKNOWN_SCALE ? this._currentScale : _ui_utils.DEFAULT_SCALE;
  202. }
  203. set currentScale(val) {
  204. if (isNaN(val)) {
  205. throw new Error("Invalid numeric scale.");
  206. }
  207. if (!this.pdfDocument) {
  208. return;
  209. }
  210. this._setScale(val, false);
  211. }
  212. get currentScaleValue() {
  213. return this._currentScaleValue;
  214. }
  215. set currentScaleValue(val) {
  216. if (!this.pdfDocument) {
  217. return;
  218. }
  219. this._setScale(val, false);
  220. }
  221. get pagesRotation() {
  222. return this._pagesRotation;
  223. }
  224. set pagesRotation(rotation) {
  225. if (!(0, _ui_utils.isValidRotation)(rotation)) {
  226. throw new Error("Invalid pages rotation angle.");
  227. }
  228. if (!this.pdfDocument) {
  229. return;
  230. }
  231. rotation %= 360;
  232. if (rotation < 0) {
  233. rotation += 360;
  234. }
  235. if (this._pagesRotation === rotation) {
  236. return;
  237. }
  238. this._pagesRotation = rotation;
  239. const pageNumber = this._currentPageNumber;
  240. for (let i = 0, ii = this._pages.length; i < ii; i++) {
  241. const pageView = this._pages[i];
  242. pageView.update(pageView.scale, rotation);
  243. }
  244. if (this._currentScaleValue) {
  245. this._setScale(this._currentScaleValue, true);
  246. }
  247. this.eventBus.dispatch("rotationchanging", {
  248. source: this,
  249. pagesRotation: rotation,
  250. pageNumber
  251. });
  252. if (this.defaultRenderingQueue) {
  253. this.update();
  254. }
  255. }
  256. get firstPagePromise() {
  257. return this.pdfDocument ? this._firstPageCapability.promise : null;
  258. }
  259. get onePageRendered() {
  260. return this.pdfDocument ? this._onePageRenderedCapability.promise : null;
  261. }
  262. get pagesPromise() {
  263. return this.pdfDocument ? this._pagesCapability.promise : null;
  264. }
  265. get _viewerElement() {
  266. throw new Error("Not implemented: _viewerElement");
  267. }
  268. _onePageRenderedOrForceFetch() {
  269. if (!this.container.offsetParent || this._getVisiblePages().views.length === 0) {
  270. return Promise.resolve();
  271. }
  272. return this._onePageRenderedCapability.promise;
  273. }
  274. setDocument(pdfDocument) {
  275. if (this.pdfDocument) {
  276. this.eventBus.dispatch("pagesdestroy", {
  277. source: this
  278. });
  279. this._cancelRendering();
  280. this._resetView();
  281. if (this.findController) {
  282. this.findController.setDocument(null);
  283. }
  284. if (this._scriptingManager) {
  285. this._scriptingManager.setDocument(null);
  286. }
  287. }
  288. this.pdfDocument = pdfDocument;
  289. if (!pdfDocument) {
  290. return;
  291. }
  292. const isPureXfa = pdfDocument.isPureXfa;
  293. const pagesCount = pdfDocument.numPages;
  294. const firstPagePromise = pdfDocument.getPage(1);
  295. const optionalContentConfigPromise = pdfDocument.getOptionalContentConfig();
  296. this._pagesCapability.promise.then(() => {
  297. this.eventBus.dispatch("pagesloaded", {
  298. source: this,
  299. pagesCount
  300. });
  301. });
  302. this._onBeforeDraw = evt => {
  303. const pageView = this._pages[evt.pageNumber - 1];
  304. if (!pageView) {
  305. return;
  306. }
  307. this._buffer.push(pageView);
  308. };
  309. this.eventBus._on("pagerender", this._onBeforeDraw);
  310. this._onAfterDraw = evt => {
  311. if (evt.cssTransform || this._onePageRenderedCapability.settled) {
  312. return;
  313. }
  314. this._onePageRenderedCapability.resolve();
  315. this.eventBus._off("pagerendered", this._onAfterDraw);
  316. this._onAfterDraw = null;
  317. };
  318. this.eventBus._on("pagerendered", this._onAfterDraw);
  319. firstPagePromise.then(firstPdfPage => {
  320. this._firstPageCapability.resolve(firstPdfPage);
  321. this._optionalContentConfigPromise = optionalContentConfigPromise;
  322. const scale = this.currentScale;
  323. const viewport = firstPdfPage.getViewport({
  324. scale: scale * _ui_utils.CSS_UNITS
  325. });
  326. const textLayerFactory = this.textLayerMode !== _ui_utils.TextLayerMode.DISABLE ? this : null;
  327. const xfaLayerFactory = isPureXfa ? this : null;
  328. for (let pageNum = 1; pageNum <= pagesCount; ++pageNum) {
  329. const pageView = new _pdf_page_view.PDFPageView({
  330. container: this._viewerElement,
  331. eventBus: this.eventBus,
  332. id: pageNum,
  333. scale,
  334. defaultViewport: viewport.clone(),
  335. optionalContentConfigPromise,
  336. renderingQueue: this.renderingQueue,
  337. textLayerFactory,
  338. textLayerMode: this.textLayerMode,
  339. annotationLayerFactory: this,
  340. xfaLayerFactory,
  341. imageResourcesPath: this.imageResourcesPath,
  342. renderInteractiveForms: this.renderInteractiveForms,
  343. renderer: this.renderer,
  344. enableWebGL: this.enableWebGL,
  345. useOnlyCssZoom: this.useOnlyCssZoom,
  346. maxCanvasPixels: this.maxCanvasPixels,
  347. l10n: this.l10n,
  348. enableScripting: this.enableScripting
  349. });
  350. this._pages.push(pageView);
  351. }
  352. const firstPageView = this._pages[0];
  353. if (firstPageView) {
  354. firstPageView.setPdfPage(firstPdfPage);
  355. this.linkService.cachePageRef(1, firstPdfPage.ref);
  356. }
  357. if (this._spreadMode !== _ui_utils.SpreadMode.NONE) {
  358. this._updateSpreadMode();
  359. }
  360. this._onePageRenderedOrForceFetch().then(() => {
  361. if (this.findController) {
  362. this.findController.setDocument(pdfDocument);
  363. }
  364. if (this.enableScripting) {
  365. this._scriptingManager.setDocument(pdfDocument);
  366. }
  367. if (pdfDocument.loadingParams.disableAutoFetch || pagesCount > 7500) {
  368. this._pagesCapability.resolve();
  369. return;
  370. }
  371. let getPagesLeft = pagesCount - 1;
  372. if (getPagesLeft <= 0) {
  373. this._pagesCapability.resolve();
  374. return;
  375. }
  376. for (let pageNum = 2; pageNum <= pagesCount; ++pageNum) {
  377. pdfDocument.getPage(pageNum).then(pdfPage => {
  378. const pageView = this._pages[pageNum - 1];
  379. if (!pageView.pdfPage) {
  380. pageView.setPdfPage(pdfPage);
  381. }
  382. this.linkService.cachePageRef(pageNum, pdfPage.ref);
  383. if (--getPagesLeft === 0) {
  384. this._pagesCapability.resolve();
  385. }
  386. }, reason => {
  387. console.error(`Unable to get page ${pageNum} to initialize viewer`, reason);
  388. if (--getPagesLeft === 0) {
  389. this._pagesCapability.resolve();
  390. }
  391. });
  392. }
  393. });
  394. this.eventBus.dispatch("pagesinit", {
  395. source: this
  396. });
  397. if (this.defaultRenderingQueue) {
  398. this.update();
  399. }
  400. }).catch(reason => {
  401. console.error("Unable to initialize viewer", reason);
  402. });
  403. }
  404. setPageLabels(labels) {
  405. if (!this.pdfDocument) {
  406. return;
  407. }
  408. if (!labels) {
  409. this._pageLabels = null;
  410. } else if (!(Array.isArray(labels) && this.pdfDocument.numPages === labels.length)) {
  411. this._pageLabels = null;
  412. console.error(`${this._name}.setPageLabels: Invalid page labels.`);
  413. } else {
  414. this._pageLabels = labels;
  415. }
  416. for (let i = 0, ii = this._pages.length; i < ii; i++) {
  417. this._pages[i].setPageLabel(this._pageLabels?.[i] ?? null);
  418. }
  419. }
  420. _resetView() {
  421. this._pages = [];
  422. this._currentPageNumber = 1;
  423. this._currentScale = _ui_utils.UNKNOWN_SCALE;
  424. this._currentScaleValue = null;
  425. this._pageLabels = null;
  426. this._buffer = new PDFPageViewBuffer(DEFAULT_CACHE_SIZE);
  427. this._location = null;
  428. this._pagesRotation = 0;
  429. this._optionalContentConfigPromise = null;
  430. this._pagesRequests = new WeakMap();
  431. this._firstPageCapability = (0, _pdf.createPromiseCapability)();
  432. this._onePageRenderedCapability = (0, _pdf.createPromiseCapability)();
  433. this._pagesCapability = (0, _pdf.createPromiseCapability)();
  434. this._scrollMode = _ui_utils.ScrollMode.VERTICAL;
  435. this._spreadMode = _ui_utils.SpreadMode.NONE;
  436. if (this._onBeforeDraw) {
  437. this.eventBus._off("pagerender", this._onBeforeDraw);
  438. this._onBeforeDraw = null;
  439. }
  440. if (this._onAfterDraw) {
  441. this.eventBus._off("pagerendered", this._onAfterDraw);
  442. this._onAfterDraw = null;
  443. }
  444. this.viewer.textContent = "";
  445. this._updateScrollMode();
  446. }
  447. _scrollUpdate() {
  448. if (this.pagesCount === 0) {
  449. return;
  450. }
  451. this.update();
  452. }
  453. _scrollIntoView({
  454. pageDiv,
  455. pageSpot = null,
  456. pageNumber = null
  457. }) {
  458. (0, _ui_utils.scrollIntoView)(pageDiv, pageSpot);
  459. }
  460. _setScaleUpdatePages(newScale, newValue, noScroll = false, preset = false) {
  461. this._currentScaleValue = newValue.toString();
  462. if (isSameScale(this._currentScale, newScale)) {
  463. if (preset) {
  464. this.eventBus.dispatch("scalechanging", {
  465. source: this,
  466. scale: newScale,
  467. presetValue: newValue
  468. });
  469. }
  470. return;
  471. }
  472. for (let i = 0, ii = this._pages.length; i < ii; i++) {
  473. this._pages[i].update(newScale);
  474. }
  475. this._currentScale = newScale;
  476. if (!noScroll) {
  477. let page = this._currentPageNumber,
  478. dest;
  479. if (this._location && !(this.isInPresentationMode || this.isChangingPresentationMode)) {
  480. page = this._location.pageNumber;
  481. dest = [null, {
  482. name: "XYZ"
  483. }, this._location.left, this._location.top, null];
  484. }
  485. this.scrollPageIntoView({
  486. pageNumber: page,
  487. destArray: dest,
  488. allowNegativeOffset: true
  489. });
  490. }
  491. this.eventBus.dispatch("scalechanging", {
  492. source: this,
  493. scale: newScale,
  494. presetValue: preset ? newValue : undefined
  495. });
  496. if (this.defaultRenderingQueue) {
  497. this.update();
  498. }
  499. }
  500. get _pageWidthScaleFactor() {
  501. if (this._spreadMode !== _ui_utils.SpreadMode.NONE && this._scrollMode !== _ui_utils.ScrollMode.HORIZONTAL && !this.isInPresentationMode) {
  502. return 2;
  503. }
  504. return 1;
  505. }
  506. _setScale(value, noScroll = false) {
  507. let scale = parseFloat(value);
  508. if (scale > 0) {
  509. this._setScaleUpdatePages(scale, value, noScroll, false);
  510. } else {
  511. const currentPage = this._pages[this._currentPageNumber - 1];
  512. if (!currentPage) {
  513. return;
  514. }
  515. const noPadding = this.isInPresentationMode || this.removePageBorders;
  516. let hPadding = noPadding ? 0 : _ui_utils.SCROLLBAR_PADDING;
  517. let vPadding = noPadding ? 0 : _ui_utils.VERTICAL_PADDING;
  518. if (!noPadding && this._isScrollModeHorizontal) {
  519. [hPadding, vPadding] = [vPadding, hPadding];
  520. }
  521. const pageWidthScale = (this.container.clientWidth - hPadding) / currentPage.width * currentPage.scale / this._pageWidthScaleFactor;
  522. const pageHeightScale = (this.container.clientHeight - vPadding) / currentPage.height * currentPage.scale;
  523. switch (value) {
  524. case "page-actual":
  525. scale = 1;
  526. break;
  527. case "page-width":
  528. scale = pageWidthScale;
  529. break;
  530. case "page-height":
  531. scale = pageHeightScale;
  532. break;
  533. case "page-fit":
  534. scale = Math.min(pageWidthScale, pageHeightScale);
  535. break;
  536. case "auto":
  537. const horizontalScale = (0, _ui_utils.isPortraitOrientation)(currentPage) ? pageWidthScale : Math.min(pageHeightScale, pageWidthScale);
  538. scale = Math.min(_ui_utils.MAX_AUTO_SCALE, horizontalScale);
  539. break;
  540. default:
  541. console.error(`${this._name}._setScale: "${value}" is an unknown zoom value.`);
  542. return;
  543. }
  544. this._setScaleUpdatePages(scale, value, noScroll, true);
  545. }
  546. }
  547. _resetCurrentPageView() {
  548. if (this.isInPresentationMode) {
  549. this._setScale(this._currentScaleValue, true);
  550. }
  551. const pageView = this._pages[this._currentPageNumber - 1];
  552. this._scrollIntoView({
  553. pageDiv: pageView.div
  554. });
  555. }
  556. pageLabelToPageNumber(label) {
  557. if (!this._pageLabels) {
  558. return null;
  559. }
  560. const i = this._pageLabels.indexOf(label);
  561. if (i < 0) {
  562. return null;
  563. }
  564. return i + 1;
  565. }
  566. scrollPageIntoView({
  567. pageNumber,
  568. destArray = null,
  569. allowNegativeOffset = false,
  570. ignoreDestinationZoom = false
  571. }) {
  572. if (!this.pdfDocument) {
  573. return;
  574. }
  575. const pageView = Number.isInteger(pageNumber) && this._pages[pageNumber - 1];
  576. if (!pageView) {
  577. console.error(`${this._name}.scrollPageIntoView: ` + `"${pageNumber}" is not a valid pageNumber parameter.`);
  578. return;
  579. }
  580. if (this.isInPresentationMode || !destArray) {
  581. this._setCurrentPageNumber(pageNumber, true);
  582. return;
  583. }
  584. let x = 0,
  585. y = 0;
  586. let width = 0,
  587. height = 0,
  588. widthScale,
  589. heightScale;
  590. const changeOrientation = pageView.rotation % 180 !== 0;
  591. const pageWidth = (changeOrientation ? pageView.height : pageView.width) / pageView.scale / _ui_utils.CSS_UNITS;
  592. const pageHeight = (changeOrientation ? pageView.width : pageView.height) / pageView.scale / _ui_utils.CSS_UNITS;
  593. let scale = 0;
  594. switch (destArray[1].name) {
  595. case "XYZ":
  596. x = destArray[2];
  597. y = destArray[3];
  598. scale = destArray[4];
  599. x = x !== null ? x : 0;
  600. y = y !== null ? y : pageHeight;
  601. break;
  602. case "Fit":
  603. case "FitB":
  604. scale = "page-fit";
  605. break;
  606. case "FitH":
  607. case "FitBH":
  608. y = destArray[2];
  609. scale = "page-width";
  610. if (y === null && this._location) {
  611. x = this._location.left;
  612. y = this._location.top;
  613. } else if (typeof y !== "number") {
  614. y = pageHeight;
  615. }
  616. break;
  617. case "FitV":
  618. case "FitBV":
  619. x = destArray[2];
  620. width = pageWidth;
  621. height = pageHeight;
  622. scale = "page-height";
  623. break;
  624. case "FitR":
  625. x = destArray[2];
  626. y = destArray[3];
  627. width = destArray[4] - x;
  628. height = destArray[5] - y;
  629. const hPadding = this.removePageBorders ? 0 : _ui_utils.SCROLLBAR_PADDING;
  630. const vPadding = this.removePageBorders ? 0 : _ui_utils.VERTICAL_PADDING;
  631. widthScale = (this.container.clientWidth - hPadding) / width / _ui_utils.CSS_UNITS;
  632. heightScale = (this.container.clientHeight - vPadding) / height / _ui_utils.CSS_UNITS;
  633. scale = Math.min(Math.abs(widthScale), Math.abs(heightScale));
  634. break;
  635. default:
  636. console.error(`${this._name}.scrollPageIntoView: ` + `"${destArray[1].name}" is not a valid destination type.`);
  637. return;
  638. }
  639. if (!ignoreDestinationZoom) {
  640. if (scale && scale !== this._currentScale) {
  641. this.currentScaleValue = scale;
  642. } else if (this._currentScale === _ui_utils.UNKNOWN_SCALE) {
  643. this.currentScaleValue = _ui_utils.DEFAULT_SCALE_VALUE;
  644. }
  645. }
  646. if (scale === "page-fit" && !destArray[4]) {
  647. this._scrollIntoView({
  648. pageDiv: pageView.div,
  649. pageNumber
  650. });
  651. return;
  652. }
  653. const boundingRect = [pageView.viewport.convertToViewportPoint(x, y), pageView.viewport.convertToViewportPoint(x + width, y + height)];
  654. let left = Math.min(boundingRect[0][0], boundingRect[1][0]);
  655. let top = Math.min(boundingRect[0][1], boundingRect[1][1]);
  656. if (!allowNegativeOffset) {
  657. left = Math.max(left, 0);
  658. top = Math.max(top, 0);
  659. }
  660. this._scrollIntoView({
  661. pageDiv: pageView.div,
  662. pageSpot: {
  663. left,
  664. top
  665. },
  666. pageNumber
  667. });
  668. }
  669. _updateLocation(firstPage) {
  670. const currentScale = this._currentScale;
  671. const currentScaleValue = this._currentScaleValue;
  672. const normalizedScaleValue = parseFloat(currentScaleValue) === currentScale ? Math.round(currentScale * 10000) / 100 : currentScaleValue;
  673. const pageNumber = firstPage.id;
  674. let pdfOpenParams = "#page=" + pageNumber;
  675. pdfOpenParams += "&zoom=" + normalizedScaleValue;
  676. const currentPageView = this._pages[pageNumber - 1];
  677. const container = this.container;
  678. const topLeft = currentPageView.getPagePoint(container.scrollLeft - firstPage.x, container.scrollTop - firstPage.y);
  679. const intLeft = Math.round(topLeft[0]);
  680. const intTop = Math.round(topLeft[1]);
  681. pdfOpenParams += "," + intLeft + "," + intTop;
  682. this._location = {
  683. pageNumber,
  684. scale: normalizedScaleValue,
  685. top: intTop,
  686. left: intLeft,
  687. rotation: this._pagesRotation,
  688. pdfOpenParams
  689. };
  690. }
  691. _updateHelper(visiblePages) {
  692. throw new Error("Not implemented: _updateHelper");
  693. }
  694. update() {
  695. const visible = this._getVisiblePages();
  696. const visiblePages = visible.views,
  697. numVisiblePages = visiblePages.length;
  698. if (numVisiblePages === 0) {
  699. return;
  700. }
  701. const newCacheSize = Math.max(DEFAULT_CACHE_SIZE, 2 * numVisiblePages + 1);
  702. this._buffer.resize(newCacheSize, visiblePages);
  703. this.renderingQueue.renderHighestPriority(visible);
  704. this._updateHelper(visiblePages);
  705. this._updateLocation(visible.first);
  706. this.eventBus.dispatch("updateviewarea", {
  707. source: this,
  708. location: this._location
  709. });
  710. }
  711. containsElement(element) {
  712. return this.container.contains(element);
  713. }
  714. focus() {
  715. this.container.focus();
  716. }
  717. get _isScrollModeHorizontal() {
  718. return this.isInPresentationMode ? false : this._scrollMode === _ui_utils.ScrollMode.HORIZONTAL;
  719. }
  720. get _isContainerRtl() {
  721. return getComputedStyle(this.container).direction === "rtl";
  722. }
  723. get isInPresentationMode() {
  724. return this.presentationModeState === _ui_utils.PresentationModeState.FULLSCREEN;
  725. }
  726. get isChangingPresentationMode() {
  727. return this.presentationModeState === _ui_utils.PresentationModeState.CHANGING;
  728. }
  729. get isHorizontalScrollbarEnabled() {
  730. return this.isInPresentationMode ? false : this.container.scrollWidth > this.container.clientWidth;
  731. }
  732. get isVerticalScrollbarEnabled() {
  733. return this.isInPresentationMode ? false : this.container.scrollHeight > this.container.clientHeight;
  734. }
  735. _getCurrentVisiblePage() {
  736. if (!this.pagesCount) {
  737. return {
  738. views: []
  739. };
  740. }
  741. const pageView = this._pages[this._currentPageNumber - 1];
  742. const element = pageView.div;
  743. const view = {
  744. id: pageView.id,
  745. x: element.offsetLeft + element.clientLeft,
  746. y: element.offsetTop + element.clientTop,
  747. view: pageView
  748. };
  749. return {
  750. first: view,
  751. last: view,
  752. views: [view]
  753. };
  754. }
  755. _getVisiblePages() {
  756. return (0, _ui_utils.getVisibleElements)({
  757. scrollEl: this.container,
  758. views: this._pages,
  759. sortByVisibility: true,
  760. horizontal: this._isScrollModeHorizontal,
  761. rtl: this._isScrollModeHorizontal && this._isContainerRtl
  762. });
  763. }
  764. isPageVisible(pageNumber) {
  765. if (!this.pdfDocument) {
  766. return false;
  767. }
  768. if (!(Number.isInteger(pageNumber) && pageNumber > 0 && pageNumber <= this.pagesCount)) {
  769. console.error(`${this._name}.isPageVisible: "${pageNumber}" is not a valid page.`);
  770. return false;
  771. }
  772. return this._getVisiblePages().views.some(function (view) {
  773. return view.id === pageNumber;
  774. });
  775. }
  776. isPageCached(pageNumber) {
  777. if (!this.pdfDocument || !this._buffer) {
  778. return false;
  779. }
  780. if (!(Number.isInteger(pageNumber) && pageNumber > 0 && pageNumber <= this.pagesCount)) {
  781. console.error(`${this._name}.isPageCached: "${pageNumber}" is not a valid page.`);
  782. return false;
  783. }
  784. const pageView = this._pages[pageNumber - 1];
  785. if (!pageView) {
  786. return false;
  787. }
  788. return this._buffer.has(pageView);
  789. }
  790. cleanup() {
  791. for (let i = 0, ii = this._pages.length; i < ii; i++) {
  792. if (this._pages[i] && this._pages[i].renderingState !== _pdf_rendering_queue.RenderingStates.FINISHED) {
  793. this._pages[i].reset();
  794. }
  795. }
  796. }
  797. _cancelRendering() {
  798. for (let i = 0, ii = this._pages.length; i < ii; i++) {
  799. if (this._pages[i]) {
  800. this._pages[i].cancelRendering();
  801. }
  802. }
  803. }
  804. _ensurePdfPageLoaded(pageView) {
  805. if (pageView.pdfPage) {
  806. return Promise.resolve(pageView.pdfPage);
  807. }
  808. if (this._pagesRequests.has(pageView)) {
  809. return this._pagesRequests.get(pageView);
  810. }
  811. const promise = this.pdfDocument.getPage(pageView.id).then(pdfPage => {
  812. if (!pageView.pdfPage) {
  813. pageView.setPdfPage(pdfPage);
  814. }
  815. this._pagesRequests.delete(pageView);
  816. return pdfPage;
  817. }).catch(reason => {
  818. console.error("Unable to get page for page view", reason);
  819. this._pagesRequests.delete(pageView);
  820. });
  821. this._pagesRequests.set(pageView, promise);
  822. return promise;
  823. }
  824. forceRendering(currentlyVisiblePages) {
  825. const visiblePages = currentlyVisiblePages || this._getVisiblePages();
  826. const scrollAhead = this._isScrollModeHorizontal ? this.scroll.right : this.scroll.down;
  827. const pageView = this.renderingQueue.getHighestPriority(visiblePages, this._pages, scrollAhead);
  828. if (pageView) {
  829. this._ensurePdfPageLoaded(pageView).then(() => {
  830. this.renderingQueue.renderView(pageView);
  831. });
  832. return true;
  833. }
  834. return false;
  835. }
  836. createTextLayerBuilder(textLayerDiv, pageIndex, viewport, enhanceTextSelection = false, eventBus) {
  837. return new _text_layer_builder.TextLayerBuilder({
  838. textLayerDiv,
  839. eventBus,
  840. pageIndex,
  841. viewport,
  842. findController: this.isInPresentationMode ? null : this.findController,
  843. enhanceTextSelection: this.isInPresentationMode ? false : enhanceTextSelection
  844. });
  845. }
  846. createAnnotationLayerBuilder(pageDiv, pdfPage, annotationStorage = null, imageResourcesPath = "", renderInteractiveForms = false, l10n = _l10n_utils.NullL10n, enableScripting = false, hasJSActionsPromise = null, mouseState = null) {
  847. return new _annotation_layer_builder.AnnotationLayerBuilder({
  848. pageDiv,
  849. pdfPage,
  850. annotationStorage: annotationStorage || this.pdfDocument?.annotationStorage,
  851. imageResourcesPath,
  852. renderInteractiveForms,
  853. linkService: this.linkService,
  854. downloadManager: this.downloadManager,
  855. l10n,
  856. enableScripting,
  857. hasJSActionsPromise: hasJSActionsPromise || this.pdfDocument?.hasJSActions(),
  858. mouseState: mouseState || this._scriptingManager?.mouseState
  859. });
  860. }
  861. createXfaLayerBuilder(pageDiv, pdfPage) {
  862. return new _xfa_layer_builder.XfaLayerBuilder({
  863. pageDiv,
  864. pdfPage
  865. });
  866. }
  867. get hasEqualPageSizes() {
  868. const firstPageView = this._pages[0];
  869. for (let i = 1, ii = this._pages.length; i < ii; ++i) {
  870. const pageView = this._pages[i];
  871. if (pageView.width !== firstPageView.width || pageView.height !== firstPageView.height) {
  872. return false;
  873. }
  874. }
  875. return true;
  876. }
  877. getPagesOverview() {
  878. return this._pages.map(pageView => {
  879. const viewport = pageView.pdfPage.getViewport({
  880. scale: 1
  881. });
  882. if (!this.enablePrintAutoRotate || (0, _ui_utils.isPortraitOrientation)(viewport)) {
  883. return {
  884. width: viewport.width,
  885. height: viewport.height,
  886. rotation: viewport.rotation
  887. };
  888. }
  889. return {
  890. width: viewport.height,
  891. height: viewport.width,
  892. rotation: (viewport.rotation - 90) % 360
  893. };
  894. });
  895. }
  896. get optionalContentConfigPromise() {
  897. if (!this.pdfDocument) {
  898. return Promise.resolve(null);
  899. }
  900. if (!this._optionalContentConfigPromise) {
  901. return this.pdfDocument.getOptionalContentConfig();
  902. }
  903. return this._optionalContentConfigPromise;
  904. }
  905. set optionalContentConfigPromise(promise) {
  906. if (!(promise instanceof Promise)) {
  907. throw new Error(`Invalid optionalContentConfigPromise: ${promise}`);
  908. }
  909. if (!this.pdfDocument) {
  910. return;
  911. }
  912. if (!this._optionalContentConfigPromise) {
  913. return;
  914. }
  915. this._optionalContentConfigPromise = promise;
  916. for (const pageView of this._pages) {
  917. pageView.update(pageView.scale, pageView.rotation, promise);
  918. }
  919. this.update();
  920. this.eventBus.dispatch("optionalcontentconfigchanged", {
  921. source: this,
  922. promise
  923. });
  924. }
  925. get scrollMode() {
  926. return this._scrollMode;
  927. }
  928. set scrollMode(mode) {
  929. if (this._scrollMode === mode) {
  930. return;
  931. }
  932. if (!(0, _ui_utils.isValidScrollMode)(mode)) {
  933. throw new Error(`Invalid scroll mode: ${mode}`);
  934. }
  935. this._scrollMode = mode;
  936. this.eventBus.dispatch("scrollmodechanged", {
  937. source: this,
  938. mode
  939. });
  940. this._updateScrollMode(this._currentPageNumber);
  941. }
  942. _updateScrollMode(pageNumber = null) {
  943. const scrollMode = this._scrollMode,
  944. viewer = this.viewer;
  945. viewer.classList.toggle("scrollHorizontal", scrollMode === _ui_utils.ScrollMode.HORIZONTAL);
  946. viewer.classList.toggle("scrollWrapped", scrollMode === _ui_utils.ScrollMode.WRAPPED);
  947. if (!this.pdfDocument || !pageNumber) {
  948. return;
  949. }
  950. if (this._currentScaleValue && isNaN(this._currentScaleValue)) {
  951. this._setScale(this._currentScaleValue, true);
  952. }
  953. this._setCurrentPageNumber(pageNumber, true);
  954. this.update();
  955. }
  956. get spreadMode() {
  957. return this._spreadMode;
  958. }
  959. set spreadMode(mode) {
  960. if (this._spreadMode === mode) {
  961. return;
  962. }
  963. if (!(0, _ui_utils.isValidSpreadMode)(mode)) {
  964. throw new Error(`Invalid spread mode: ${mode}`);
  965. }
  966. this._spreadMode = mode;
  967. this.eventBus.dispatch("spreadmodechanged", {
  968. source: this,
  969. mode
  970. });
  971. this._updateSpreadMode(this._currentPageNumber);
  972. }
  973. _updateSpreadMode(pageNumber = null) {
  974. if (!this.pdfDocument) {
  975. return;
  976. }
  977. const viewer = this.viewer,
  978. pages = this._pages;
  979. viewer.textContent = "";
  980. if (this._spreadMode === _ui_utils.SpreadMode.NONE) {
  981. for (let i = 0, iMax = pages.length; i < iMax; ++i) {
  982. viewer.appendChild(pages[i].div);
  983. }
  984. } else {
  985. const parity = this._spreadMode - 1;
  986. let spread = null;
  987. for (let i = 0, iMax = pages.length; i < iMax; ++i) {
  988. if (spread === null) {
  989. spread = document.createElement("div");
  990. spread.className = "spread";
  991. viewer.appendChild(spread);
  992. } else if (i % 2 === parity) {
  993. spread = spread.cloneNode(false);
  994. viewer.appendChild(spread);
  995. }
  996. spread.appendChild(pages[i].div);
  997. }
  998. }
  999. if (!pageNumber) {
  1000. return;
  1001. }
  1002. if (this._currentScaleValue && isNaN(this._currentScaleValue)) {
  1003. this._setScale(this._currentScaleValue, true);
  1004. }
  1005. this._setCurrentPageNumber(pageNumber, true);
  1006. this.update();
  1007. }
  1008. _getPageAdvance(currentPageNumber, previous = false) {
  1009. if (this.isInPresentationMode) {
  1010. return 1;
  1011. }
  1012. switch (this._scrollMode) {
  1013. case _ui_utils.ScrollMode.WRAPPED:
  1014. {
  1015. const {
  1016. views
  1017. } = this._getVisiblePages(),
  1018. pageLayout = new Map();
  1019. for (const {
  1020. id,
  1021. y,
  1022. percent,
  1023. widthPercent
  1024. } of views) {
  1025. if (percent === 0 || widthPercent < 100) {
  1026. continue;
  1027. }
  1028. let yArray = pageLayout.get(y);
  1029. if (!yArray) {
  1030. pageLayout.set(y, yArray || (yArray = []));
  1031. }
  1032. yArray.push(id);
  1033. }
  1034. for (const yArray of pageLayout.values()) {
  1035. const currentIndex = yArray.indexOf(currentPageNumber);
  1036. if (currentIndex === -1) {
  1037. continue;
  1038. }
  1039. const numPages = yArray.length;
  1040. if (numPages === 1) {
  1041. break;
  1042. }
  1043. if (previous) {
  1044. for (let i = currentIndex - 1, ii = 0; i >= ii; i--) {
  1045. const currentId = yArray[i],
  1046. expectedId = yArray[i + 1] - 1;
  1047. if (currentId < expectedId) {
  1048. return currentPageNumber - expectedId;
  1049. }
  1050. }
  1051. } else {
  1052. for (let i = currentIndex + 1, ii = numPages; i < ii; i++) {
  1053. const currentId = yArray[i],
  1054. expectedId = yArray[i - 1] + 1;
  1055. if (currentId > expectedId) {
  1056. return expectedId - currentPageNumber;
  1057. }
  1058. }
  1059. }
  1060. if (previous) {
  1061. const firstId = yArray[0];
  1062. if (firstId < currentPageNumber) {
  1063. return currentPageNumber - firstId + 1;
  1064. }
  1065. } else {
  1066. const lastId = yArray[numPages - 1];
  1067. if (lastId > currentPageNumber) {
  1068. return lastId - currentPageNumber + 1;
  1069. }
  1070. }
  1071. break;
  1072. }
  1073. break;
  1074. }
  1075. case _ui_utils.ScrollMode.HORIZONTAL:
  1076. {
  1077. break;
  1078. }
  1079. case _ui_utils.ScrollMode.VERTICAL:
  1080. {
  1081. if (this._spreadMode === _ui_utils.SpreadMode.NONE) {
  1082. break;
  1083. }
  1084. const parity = this._spreadMode - 1;
  1085. if (previous && currentPageNumber % 2 !== parity) {
  1086. break;
  1087. } else if (!previous && currentPageNumber % 2 === parity) {
  1088. break;
  1089. }
  1090. const {
  1091. views
  1092. } = this._getVisiblePages(),
  1093. expectedId = previous ? currentPageNumber - 1 : currentPageNumber + 1;
  1094. for (const {
  1095. id,
  1096. percent,
  1097. widthPercent
  1098. } of views) {
  1099. if (id !== expectedId) {
  1100. continue;
  1101. }
  1102. if (percent > 0 && widthPercent === 100) {
  1103. return 2;
  1104. }
  1105. break;
  1106. }
  1107. break;
  1108. }
  1109. }
  1110. return 1;
  1111. }
  1112. nextPage() {
  1113. const currentPageNumber = this._currentPageNumber,
  1114. pagesCount = this.pagesCount;
  1115. if (currentPageNumber >= pagesCount) {
  1116. return false;
  1117. }
  1118. const advance = this._getPageAdvance(currentPageNumber, false) || 1;
  1119. this.currentPageNumber = Math.min(currentPageNumber + advance, pagesCount);
  1120. return true;
  1121. }
  1122. previousPage() {
  1123. const currentPageNumber = this._currentPageNumber;
  1124. if (currentPageNumber <= 1) {
  1125. return false;
  1126. }
  1127. const advance = this._getPageAdvance(currentPageNumber, true) || 1;
  1128. this.currentPageNumber = Math.max(currentPageNumber - advance, 1);
  1129. return true;
  1130. }
  1131. }
  1132. exports.BaseViewer = BaseViewer;