base_viewer.js 29 KB

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