pdf_page_view.js 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848
  1. /**
  2. * @licstart The following is the entire license notice for the
  3. * JavaScript code in this page
  4. *
  5. * Copyright 2022 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.PDFPageView = void 0;
  27. var _pdf = require("../pdf");
  28. var _ui_utils = require("./ui_utils.js");
  29. var _annotation_editor_layer_builder = require("./annotation_editor_layer_builder.js");
  30. var _annotation_layer_builder = require("./annotation_layer_builder.js");
  31. var _app_options = require("./app_options.js");
  32. var _l10n_utils = require("./l10n_utils.js");
  33. var _struct_tree_layer_builder = require("./struct_tree_layer_builder.js");
  34. var _text_accessibility = require("./text_accessibility.js");
  35. var _text_highlighter = require("./text_highlighter.js");
  36. var _text_layer_builder = require("./text_layer_builder.js");
  37. var _xfa_layer_builder = require("./xfa_layer_builder.js");
  38. const MAX_CANVAS_PIXELS = _app_options.compatibilityParams.maxCanvasPixels || 16777216;
  39. const DEFAULT_LAYER_PROPERTIES = () => {
  40. return null;
  41. };
  42. class PDFPageView {
  43. #annotationMode = _pdf.AnnotationMode.ENABLE_FORMS;
  44. #layerProperties = null;
  45. #previousRotation = null;
  46. #renderingState = _ui_utils.RenderingStates.INITIAL;
  47. #useThumbnailCanvas = {
  48. initialOptionalContent: true,
  49. regularAnnotations: true
  50. };
  51. constructor(options) {
  52. const container = options.container;
  53. const defaultViewport = options.defaultViewport;
  54. this.id = options.id;
  55. this.renderingId = "page" + this.id;
  56. this.#layerProperties = options.layerProperties || DEFAULT_LAYER_PROPERTIES;
  57. this.pdfPage = null;
  58. this.pageLabel = null;
  59. this.rotation = 0;
  60. this.scale = options.scale || _ui_utils.DEFAULT_SCALE;
  61. this.viewport = defaultViewport;
  62. this.pdfPageRotate = defaultViewport.rotation;
  63. this._optionalContentConfigPromise = options.optionalContentConfigPromise || null;
  64. this.hasRestrictedScaling = false;
  65. this.textLayerMode = options.textLayerMode ?? _ui_utils.TextLayerMode.ENABLE;
  66. this.#annotationMode = options.annotationMode ?? _pdf.AnnotationMode.ENABLE_FORMS;
  67. this.imageResourcesPath = options.imageResourcesPath || "";
  68. this.useOnlyCssZoom = options.useOnlyCssZoom || false;
  69. this.isOffscreenCanvasSupported = options.isOffscreenCanvasSupported ?? true;
  70. this.maxCanvasPixels = options.maxCanvasPixels || MAX_CANVAS_PIXELS;
  71. this.pageColors = options.pageColors || null;
  72. this.eventBus = options.eventBus;
  73. this.renderingQueue = options.renderingQueue;
  74. this.renderer = options.renderer || _ui_utils.RendererType.CANVAS;
  75. this.l10n = options.l10n || _l10n_utils.NullL10n;
  76. this.paintTask = null;
  77. this.paintedViewportMap = new WeakMap();
  78. this.resume = null;
  79. this._renderError = null;
  80. this._isStandalone = !this.renderingQueue?.hasViewer();
  81. this._annotationCanvasMap = null;
  82. this.annotationLayer = null;
  83. this.annotationEditorLayer = null;
  84. this.textLayer = null;
  85. this.zoomLayer = null;
  86. this.xfaLayer = null;
  87. this.structTreeLayer = null;
  88. const div = document.createElement("div");
  89. div.className = "page";
  90. div.setAttribute("data-page-number", this.id);
  91. div.setAttribute("role", "region");
  92. this.l10n.get("page_landmark", {
  93. page: this.id
  94. }).then(msg => {
  95. div.setAttribute("aria-label", msg);
  96. });
  97. this.div = div;
  98. this.#setDimensions();
  99. container?.append(div);
  100. if (this._isStandalone) {
  101. _ui_utils.docStyle.setProperty("--scale-factor", this.scale * _pdf.PixelsPerInch.PDF_TO_CSS_UNITS);
  102. const {
  103. optionalContentConfigPromise
  104. } = options;
  105. if (optionalContentConfigPromise) {
  106. optionalContentConfigPromise.then(optionalContentConfig => {
  107. if (optionalContentConfigPromise !== this._optionalContentConfigPromise) {
  108. return;
  109. }
  110. this.#useThumbnailCanvas.initialOptionalContent = optionalContentConfig.hasInitialVisibility;
  111. });
  112. }
  113. }
  114. }
  115. get renderingState() {
  116. return this.#renderingState;
  117. }
  118. set renderingState(state) {
  119. this.#renderingState = state;
  120. switch (state) {
  121. case _ui_utils.RenderingStates.INITIAL:
  122. case _ui_utils.RenderingStates.PAUSED:
  123. this.loadingIconDiv?.classList.add("notVisible");
  124. break;
  125. case _ui_utils.RenderingStates.RUNNING:
  126. this.loadingIconDiv?.classList.remove("notVisible");
  127. break;
  128. case _ui_utils.RenderingStates.FINISHED:
  129. if (this.loadingIconDiv) {
  130. this.loadingIconDiv.remove();
  131. delete this.loadingIconDiv;
  132. }
  133. break;
  134. }
  135. }
  136. #setDimensions() {
  137. const {
  138. viewport
  139. } = this;
  140. if (this.pdfPage) {
  141. if (this.#previousRotation === viewport.rotation) {
  142. return;
  143. }
  144. this.#previousRotation = viewport.rotation;
  145. }
  146. (0, _pdf.setLayerDimensions)(this.div, viewport, true, false);
  147. }
  148. setPdfPage(pdfPage) {
  149. this.pdfPage = pdfPage;
  150. this.pdfPageRotate = pdfPage.rotate;
  151. const totalRotation = (this.rotation + this.pdfPageRotate) % 360;
  152. this.viewport = pdfPage.getViewport({
  153. scale: this.scale * _pdf.PixelsPerInch.PDF_TO_CSS_UNITS,
  154. rotation: totalRotation
  155. });
  156. this.#setDimensions();
  157. this.reset();
  158. }
  159. destroy() {
  160. this.reset();
  161. this.pdfPage?.cleanup();
  162. }
  163. get _textHighlighter() {
  164. return (0, _pdf.shadow)(this, "_textHighlighter", new _text_highlighter.TextHighlighter({
  165. pageIndex: this.id - 1,
  166. eventBus: this.eventBus,
  167. findController: this.#layerProperties().findController
  168. }));
  169. }
  170. async #renderAnnotationLayer() {
  171. let error = null;
  172. try {
  173. await this.annotationLayer.render(this.viewport, "display");
  174. } catch (ex) {
  175. console.error(`#renderAnnotationLayer: "${ex}".`);
  176. error = ex;
  177. } finally {
  178. this.eventBus.dispatch("annotationlayerrendered", {
  179. source: this,
  180. pageNumber: this.id,
  181. error
  182. });
  183. }
  184. }
  185. async #renderAnnotationEditorLayer() {
  186. let error = null;
  187. try {
  188. await this.annotationEditorLayer.render(this.viewport, "display");
  189. } catch (ex) {
  190. console.error(`#renderAnnotationEditorLayer: "${ex}".`);
  191. error = ex;
  192. } finally {
  193. this.eventBus.dispatch("annotationeditorlayerrendered", {
  194. source: this,
  195. pageNumber: this.id,
  196. error
  197. });
  198. }
  199. }
  200. async #renderXfaLayer() {
  201. let error = null;
  202. try {
  203. const result = await this.xfaLayer.render(this.viewport, "display");
  204. if (result?.textDivs && this._textHighlighter) {
  205. this.#buildXfaTextContentItems(result.textDivs);
  206. }
  207. } catch (ex) {
  208. console.error(`#renderXfaLayer: "${ex}".`);
  209. error = ex;
  210. } finally {
  211. this.eventBus.dispatch("xfalayerrendered", {
  212. source: this,
  213. pageNumber: this.id,
  214. error
  215. });
  216. }
  217. }
  218. async #renderTextLayer() {
  219. const {
  220. pdfPage,
  221. textLayer,
  222. viewport
  223. } = this;
  224. if (!textLayer) {
  225. return;
  226. }
  227. let error = null;
  228. try {
  229. if (!textLayer.renderingDone) {
  230. const readableStream = pdfPage.streamTextContent({
  231. includeMarkedContent: true
  232. });
  233. textLayer.setTextContentSource(readableStream);
  234. }
  235. await textLayer.render(viewport);
  236. } catch (ex) {
  237. if (ex instanceof _pdf.AbortException) {
  238. return;
  239. }
  240. console.error(`#renderTextLayer: "${ex}".`);
  241. error = ex;
  242. }
  243. this.eventBus.dispatch("textlayerrendered", {
  244. source: this,
  245. pageNumber: this.id,
  246. numTextDivs: textLayer.numTextDivs,
  247. error
  248. });
  249. this.#renderStructTreeLayer();
  250. }
  251. async #renderStructTreeLayer() {
  252. if (!this.textLayer) {
  253. return;
  254. }
  255. this.structTreeLayer ||= new _struct_tree_layer_builder.StructTreeLayerBuilder();
  256. const tree = await (!this.structTreeLayer.renderingDone ? this.pdfPage.getStructTree() : null);
  257. const treeDom = this.structTreeLayer?.render(tree);
  258. if (treeDom) {
  259. this.canvas?.append(treeDom);
  260. }
  261. }
  262. async #buildXfaTextContentItems(textDivs) {
  263. const text = await this.pdfPage.getTextContent();
  264. const items = [];
  265. for (const item of text.items) {
  266. items.push(item.str);
  267. }
  268. this._textHighlighter.setTextMapping(textDivs, items);
  269. this._textHighlighter.enable();
  270. }
  271. _resetZoomLayer(removeFromDOM = false) {
  272. if (!this.zoomLayer) {
  273. return;
  274. }
  275. const zoomLayerCanvas = this.zoomLayer.firstChild;
  276. this.paintedViewportMap.delete(zoomLayerCanvas);
  277. zoomLayerCanvas.width = 0;
  278. zoomLayerCanvas.height = 0;
  279. if (removeFromDOM) {
  280. this.zoomLayer.remove();
  281. }
  282. this.zoomLayer = null;
  283. }
  284. reset({
  285. keepZoomLayer = false,
  286. keepAnnotationLayer = false,
  287. keepAnnotationEditorLayer = false,
  288. keepXfaLayer = false,
  289. keepTextLayer = false
  290. } = {}) {
  291. this.cancelRendering({
  292. keepAnnotationLayer,
  293. keepAnnotationEditorLayer,
  294. keepXfaLayer,
  295. keepTextLayer
  296. });
  297. this.renderingState = _ui_utils.RenderingStates.INITIAL;
  298. const div = this.div;
  299. const childNodes = div.childNodes,
  300. zoomLayerNode = keepZoomLayer && this.zoomLayer || null,
  301. annotationLayerNode = keepAnnotationLayer && this.annotationLayer?.div || null,
  302. annotationEditorLayerNode = keepAnnotationEditorLayer && this.annotationEditorLayer?.div || null,
  303. xfaLayerNode = keepXfaLayer && this.xfaLayer?.div || null,
  304. textLayerNode = keepTextLayer && this.textLayer?.div || null;
  305. for (let i = childNodes.length - 1; i >= 0; i--) {
  306. const node = childNodes[i];
  307. switch (node) {
  308. case zoomLayerNode:
  309. case annotationLayerNode:
  310. case annotationEditorLayerNode:
  311. case xfaLayerNode:
  312. case textLayerNode:
  313. case this.loadingIconDiv:
  314. continue;
  315. }
  316. node.remove();
  317. }
  318. div.removeAttribute("data-loaded");
  319. if (annotationLayerNode) {
  320. this.annotationLayer.hide();
  321. }
  322. if (annotationEditorLayerNode) {
  323. this.annotationEditorLayer.hide();
  324. }
  325. if (xfaLayerNode) {
  326. this.xfaLayer.hide();
  327. }
  328. if (textLayerNode) {
  329. this.textLayer.hide();
  330. }
  331. if (!zoomLayerNode) {
  332. if (this.canvas) {
  333. this.paintedViewportMap.delete(this.canvas);
  334. this.canvas.width = 0;
  335. this.canvas.height = 0;
  336. delete this.canvas;
  337. }
  338. this._resetZoomLayer();
  339. }
  340. if (this.svg) {
  341. this.paintedViewportMap.delete(this.svg);
  342. delete this.svg;
  343. }
  344. if (!this.loadingIconDiv) {
  345. this.loadingIconDiv = document.createElement("div");
  346. this.loadingIconDiv.className = "loadingIcon notVisible";
  347. this.loadingIconDiv.setAttribute("role", "img");
  348. this.l10n.get("loading").then(msg => {
  349. this.loadingIconDiv?.setAttribute("aria-label", msg);
  350. });
  351. div.append(this.loadingIconDiv);
  352. }
  353. }
  354. update({
  355. scale = 0,
  356. rotation = null,
  357. optionalContentConfigPromise = null,
  358. drawingDelay = -1
  359. }) {
  360. this.scale = scale || this.scale;
  361. if (typeof rotation === "number") {
  362. this.rotation = rotation;
  363. }
  364. if (optionalContentConfigPromise instanceof Promise) {
  365. this._optionalContentConfigPromise = optionalContentConfigPromise;
  366. optionalContentConfigPromise.then(optionalContentConfig => {
  367. if (optionalContentConfigPromise !== this._optionalContentConfigPromise) {
  368. return;
  369. }
  370. this.#useThumbnailCanvas.initialOptionalContent = optionalContentConfig.hasInitialVisibility;
  371. });
  372. }
  373. const totalRotation = (this.rotation + this.pdfPageRotate) % 360;
  374. this.viewport = this.viewport.clone({
  375. scale: this.scale * _pdf.PixelsPerInch.PDF_TO_CSS_UNITS,
  376. rotation: totalRotation
  377. });
  378. this.#setDimensions();
  379. if (this._isStandalone) {
  380. _ui_utils.docStyle.setProperty("--scale-factor", this.viewport.scale);
  381. }
  382. if (this.svg) {
  383. this.cssTransform({
  384. target: this.svg,
  385. redrawAnnotationLayer: true,
  386. redrawAnnotationEditorLayer: true,
  387. redrawXfaLayer: true,
  388. redrawTextLayer: true
  389. });
  390. this.eventBus.dispatch("pagerendered", {
  391. source: this,
  392. pageNumber: this.id,
  393. cssTransform: true,
  394. timestamp: performance.now(),
  395. error: this._renderError
  396. });
  397. return;
  398. }
  399. let isScalingRestricted = false;
  400. if (this.canvas && this.maxCanvasPixels > 0) {
  401. const outputScale = this.outputScale;
  402. if ((Math.floor(this.viewport.width) * outputScale.sx | 0) * (Math.floor(this.viewport.height) * outputScale.sy | 0) > this.maxCanvasPixels) {
  403. isScalingRestricted = true;
  404. }
  405. }
  406. const postponeDrawing = drawingDelay >= 0 && drawingDelay < 1000;
  407. if (this.canvas) {
  408. if (postponeDrawing || this.useOnlyCssZoom || this.hasRestrictedScaling && isScalingRestricted) {
  409. if (postponeDrawing && this.renderingState !== _ui_utils.RenderingStates.FINISHED) {
  410. this.cancelRendering({
  411. keepZoomLayer: true,
  412. keepAnnotationLayer: true,
  413. keepAnnotationEditorLayer: true,
  414. keepXfaLayer: true,
  415. keepTextLayer: true,
  416. cancelExtraDelay: drawingDelay
  417. });
  418. this.renderingState = _ui_utils.RenderingStates.FINISHED;
  419. }
  420. this.cssTransform({
  421. target: this.canvas,
  422. redrawAnnotationLayer: true,
  423. redrawAnnotationEditorLayer: true,
  424. redrawXfaLayer: true,
  425. redrawTextLayer: !postponeDrawing,
  426. hideTextLayer: postponeDrawing
  427. });
  428. this.eventBus.dispatch("pagerendered", {
  429. source: this,
  430. pageNumber: this.id,
  431. cssTransform: true,
  432. timestamp: performance.now(),
  433. error: this._renderError
  434. });
  435. return;
  436. }
  437. if (!this.zoomLayer && !this.canvas.hidden) {
  438. this.zoomLayer = this.canvas.parentNode;
  439. this.zoomLayer.style.position = "absolute";
  440. }
  441. }
  442. if (this.zoomLayer) {
  443. this.cssTransform({
  444. target: this.zoomLayer.firstChild
  445. });
  446. }
  447. this.reset({
  448. keepZoomLayer: true,
  449. keepAnnotationLayer: true,
  450. keepAnnotationEditorLayer: true,
  451. keepXfaLayer: true,
  452. keepTextLayer: true
  453. });
  454. }
  455. cancelRendering({
  456. keepAnnotationLayer = false,
  457. keepAnnotationEditorLayer = false,
  458. keepXfaLayer = false,
  459. keepTextLayer = false,
  460. cancelExtraDelay = 0
  461. } = {}) {
  462. if (this.paintTask) {
  463. this.paintTask.cancel(cancelExtraDelay);
  464. this.paintTask = null;
  465. }
  466. this.resume = null;
  467. if (this.textLayer && (!keepTextLayer || !this.textLayer.div)) {
  468. this.textLayer.cancel();
  469. this.textLayer = null;
  470. }
  471. if (this.structTreeLayer && !this.textLayer) {
  472. this.structTreeLayer = null;
  473. }
  474. if (this.annotationLayer && (!keepAnnotationLayer || !this.annotationLayer.div)) {
  475. this.annotationLayer.cancel();
  476. this.annotationLayer = null;
  477. this._annotationCanvasMap = null;
  478. }
  479. if (this.annotationEditorLayer && (!keepAnnotationEditorLayer || !this.annotationEditorLayer.div)) {
  480. this.annotationEditorLayer.cancel();
  481. this.annotationEditorLayer = null;
  482. }
  483. if (this.xfaLayer && (!keepXfaLayer || !this.xfaLayer.div)) {
  484. this.xfaLayer.cancel();
  485. this.xfaLayer = null;
  486. this._textHighlighter?.disable();
  487. }
  488. }
  489. cssTransform({
  490. target,
  491. redrawAnnotationLayer = false,
  492. redrawAnnotationEditorLayer = false,
  493. redrawXfaLayer = false,
  494. redrawTextLayer = false,
  495. hideTextLayer = false
  496. }) {
  497. if (target instanceof HTMLCanvasElement) {
  498. if (!target.hasAttribute("zooming")) {
  499. target.setAttribute("zooming", true);
  500. const {
  501. style
  502. } = target;
  503. style.width = style.height = "";
  504. }
  505. } else {
  506. const div = this.div;
  507. const {
  508. width,
  509. height
  510. } = this.viewport;
  511. target.style.width = target.parentNode.style.width = div.style.width = Math.floor(width) + "px";
  512. target.style.height = target.parentNode.style.height = div.style.height = Math.floor(height) + "px";
  513. }
  514. const originalViewport = this.paintedViewportMap.get(target);
  515. if (this.viewport !== originalViewport) {
  516. const relativeRotation = this.viewport.rotation - originalViewport.rotation;
  517. const absRotation = Math.abs(relativeRotation);
  518. let scaleX = 1,
  519. scaleY = 1;
  520. if (absRotation === 90 || absRotation === 270) {
  521. const {
  522. width,
  523. height
  524. } = this.viewport;
  525. scaleX = height / width;
  526. scaleY = width / height;
  527. }
  528. if (absRotation !== 0) {
  529. target.style.transform = `rotate(${relativeRotation}deg) scale(${scaleX}, ${scaleY})`;
  530. }
  531. }
  532. if (redrawAnnotationLayer && this.annotationLayer) {
  533. this.#renderAnnotationLayer();
  534. }
  535. if (redrawAnnotationEditorLayer && this.annotationEditorLayer) {
  536. this.#renderAnnotationEditorLayer();
  537. }
  538. if (redrawXfaLayer && this.xfaLayer) {
  539. this.#renderXfaLayer();
  540. }
  541. if (this.textLayer) {
  542. if (hideTextLayer) {
  543. this.textLayer.hide();
  544. } else if (redrawTextLayer) {
  545. this.#renderTextLayer();
  546. }
  547. }
  548. }
  549. get width() {
  550. return this.viewport.width;
  551. }
  552. get height() {
  553. return this.viewport.height;
  554. }
  555. getPagePoint(x, y) {
  556. return this.viewport.convertToPdfPoint(x, y);
  557. }
  558. draw() {
  559. if (this.renderingState !== _ui_utils.RenderingStates.INITIAL) {
  560. console.error("Must be in new state before drawing");
  561. this.reset();
  562. }
  563. const {
  564. div,
  565. pdfPage
  566. } = this;
  567. if (!pdfPage) {
  568. this.renderingState = _ui_utils.RenderingStates.FINISHED;
  569. return Promise.reject(new Error("pdfPage is not loaded"));
  570. }
  571. this.renderingState = _ui_utils.RenderingStates.RUNNING;
  572. const canvasWrapper = document.createElement("div");
  573. canvasWrapper.classList.add("canvasWrapper");
  574. div.append(canvasWrapper);
  575. if (!this.textLayer && this.textLayerMode !== _ui_utils.TextLayerMode.DISABLE && !pdfPage.isPureXfa) {
  576. this._accessibilityManager ||= new _text_accessibility.TextAccessibilityManager();
  577. this.textLayer = new _text_layer_builder.TextLayerBuilder({
  578. highlighter: this._textHighlighter,
  579. accessibilityManager: this._accessibilityManager,
  580. isOffscreenCanvasSupported: this.isOffscreenCanvasSupported
  581. });
  582. div.append(this.textLayer.div);
  583. }
  584. if (!this.annotationLayer && this.#annotationMode !== _pdf.AnnotationMode.DISABLE) {
  585. const {
  586. annotationStorage,
  587. downloadManager,
  588. enableScripting,
  589. fieldObjectsPromise,
  590. hasJSActionsPromise,
  591. linkService
  592. } = this.#layerProperties();
  593. this._annotationCanvasMap ||= new Map();
  594. this.annotationLayer = new _annotation_layer_builder.AnnotationLayerBuilder({
  595. pageDiv: div,
  596. pdfPage,
  597. annotationStorage,
  598. imageResourcesPath: this.imageResourcesPath,
  599. renderForms: this.#annotationMode === _pdf.AnnotationMode.ENABLE_FORMS,
  600. linkService,
  601. downloadManager,
  602. l10n: this.l10n,
  603. enableScripting,
  604. hasJSActionsPromise,
  605. fieldObjectsPromise,
  606. annotationCanvasMap: this._annotationCanvasMap,
  607. accessibilityManager: this._accessibilityManager
  608. });
  609. }
  610. if (this.xfaLayer?.div) {
  611. div.append(this.xfaLayer.div);
  612. }
  613. let renderContinueCallback = null;
  614. if (this.renderingQueue) {
  615. renderContinueCallback = cont => {
  616. if (!this.renderingQueue.isHighestPriority(this)) {
  617. this.renderingState = _ui_utils.RenderingStates.PAUSED;
  618. this.resume = () => {
  619. this.renderingState = _ui_utils.RenderingStates.RUNNING;
  620. cont();
  621. };
  622. return;
  623. }
  624. cont();
  625. };
  626. }
  627. const finishPaintTask = async (error = null) => {
  628. if (paintTask === this.paintTask) {
  629. this.paintTask = null;
  630. }
  631. if (error instanceof _pdf.RenderingCancelledException) {
  632. this._renderError = null;
  633. return;
  634. }
  635. this._renderError = error;
  636. this.renderingState = _ui_utils.RenderingStates.FINISHED;
  637. this._resetZoomLayer(true);
  638. this.#useThumbnailCanvas.regularAnnotations = !paintTask.separateAnnots;
  639. this.eventBus.dispatch("pagerendered", {
  640. source: this,
  641. pageNumber: this.id,
  642. cssTransform: false,
  643. timestamp: performance.now(),
  644. error: this._renderError
  645. });
  646. if (error) {
  647. throw error;
  648. }
  649. };
  650. const paintTask = this.renderer === _ui_utils.RendererType.SVG ? this.paintOnSvg(canvasWrapper) : this.paintOnCanvas(canvasWrapper);
  651. paintTask.onRenderContinue = renderContinueCallback;
  652. this.paintTask = paintTask;
  653. const resultPromise = paintTask.promise.then(() => {
  654. return finishPaintTask(null).then(async () => {
  655. this.#renderTextLayer();
  656. if (this.annotationLayer) {
  657. await this.#renderAnnotationLayer();
  658. }
  659. if (!this.annotationEditorLayer) {
  660. const {
  661. annotationEditorUIManager
  662. } = this.#layerProperties();
  663. if (!annotationEditorUIManager) {
  664. return;
  665. }
  666. this.annotationEditorLayer = new _annotation_editor_layer_builder.AnnotationEditorLayerBuilder({
  667. uiManager: annotationEditorUIManager,
  668. pageDiv: div,
  669. pdfPage,
  670. l10n: this.l10n,
  671. accessibilityManager: this._accessibilityManager
  672. });
  673. }
  674. this.#renderAnnotationEditorLayer();
  675. });
  676. }, function (reason) {
  677. return finishPaintTask(reason);
  678. });
  679. if (pdfPage.isPureXfa) {
  680. if (!this.xfaLayer) {
  681. const {
  682. annotationStorage,
  683. linkService
  684. } = this.#layerProperties();
  685. this.xfaLayer = new _xfa_layer_builder.XfaLayerBuilder({
  686. pageDiv: div,
  687. pdfPage,
  688. annotationStorage,
  689. linkService
  690. });
  691. }
  692. this.#renderXfaLayer();
  693. }
  694. div.setAttribute("data-loaded", true);
  695. this.eventBus.dispatch("pagerender", {
  696. source: this,
  697. pageNumber: this.id
  698. });
  699. return resultPromise;
  700. }
  701. paintOnCanvas(canvasWrapper) {
  702. const renderCapability = (0, _pdf.createPromiseCapability)();
  703. const result = {
  704. promise: renderCapability.promise,
  705. onRenderContinue(cont) {
  706. cont();
  707. },
  708. cancel(extraDelay = 0) {
  709. renderTask.cancel(extraDelay);
  710. },
  711. get separateAnnots() {
  712. return renderTask.separateAnnots;
  713. }
  714. };
  715. const viewport = this.viewport;
  716. const {
  717. width,
  718. height
  719. } = viewport;
  720. const canvas = document.createElement("canvas");
  721. canvas.setAttribute("role", "presentation");
  722. canvas.hidden = true;
  723. let isCanvasHidden = true;
  724. const showCanvas = function () {
  725. if (isCanvasHidden) {
  726. canvas.hidden = false;
  727. isCanvasHidden = false;
  728. }
  729. };
  730. canvasWrapper.append(canvas);
  731. this.canvas = canvas;
  732. const ctx = canvas.getContext("2d", {
  733. alpha: false
  734. });
  735. const outputScale = this.outputScale = new _ui_utils.OutputScale();
  736. if (this.useOnlyCssZoom) {
  737. const actualSizeViewport = viewport.clone({
  738. scale: _pdf.PixelsPerInch.PDF_TO_CSS_UNITS
  739. });
  740. outputScale.sx *= actualSizeViewport.width / width;
  741. outputScale.sy *= actualSizeViewport.height / height;
  742. }
  743. if (this.maxCanvasPixels > 0) {
  744. const pixelsInViewport = width * height;
  745. const maxScale = Math.sqrt(this.maxCanvasPixels / pixelsInViewport);
  746. if (outputScale.sx > maxScale || outputScale.sy > maxScale) {
  747. outputScale.sx = maxScale;
  748. outputScale.sy = maxScale;
  749. this.hasRestrictedScaling = true;
  750. } else {
  751. this.hasRestrictedScaling = false;
  752. }
  753. }
  754. const sfx = (0, _ui_utils.approximateFraction)(outputScale.sx);
  755. const sfy = (0, _ui_utils.approximateFraction)(outputScale.sy);
  756. canvas.width = (0, _ui_utils.roundToDivide)(viewport.width * outputScale.sx, sfx[0]);
  757. canvas.height = (0, _ui_utils.roundToDivide)(viewport.height * outputScale.sy, sfy[0]);
  758. const {
  759. style
  760. } = canvas;
  761. style.width = (0, _ui_utils.roundToDivide)(viewport.width, sfx[1]) + "px";
  762. style.height = (0, _ui_utils.roundToDivide)(viewport.height, sfy[1]) + "px";
  763. this.paintedViewportMap.set(canvas, viewport);
  764. const transform = outputScale.scaled ? [outputScale.sx, 0, 0, outputScale.sy, 0, 0] : null;
  765. const renderContext = {
  766. canvasContext: ctx,
  767. transform,
  768. viewport,
  769. annotationMode: this.#annotationMode,
  770. optionalContentConfigPromise: this._optionalContentConfigPromise,
  771. annotationCanvasMap: this._annotationCanvasMap,
  772. pageColors: this.pageColors
  773. };
  774. const renderTask = this.pdfPage.render(renderContext);
  775. renderTask.onContinue = function (cont) {
  776. showCanvas();
  777. if (result.onRenderContinue) {
  778. result.onRenderContinue(cont);
  779. } else {
  780. cont();
  781. }
  782. };
  783. renderTask.promise.then(function () {
  784. showCanvas();
  785. renderCapability.resolve();
  786. }, function (error) {
  787. showCanvas();
  788. renderCapability.reject(error);
  789. });
  790. return result;
  791. }
  792. paintOnSvg(wrapper) {
  793. let cancelled = false;
  794. const ensureNotCancelled = () => {
  795. if (cancelled) {
  796. throw new _pdf.RenderingCancelledException(`Rendering cancelled, page ${this.id}`, "svg");
  797. }
  798. };
  799. const pdfPage = this.pdfPage;
  800. const actualSizeViewport = this.viewport.clone({
  801. scale: _pdf.PixelsPerInch.PDF_TO_CSS_UNITS
  802. });
  803. const promise = pdfPage.getOperatorList({
  804. annotationMode: this.#annotationMode
  805. }).then(opList => {
  806. ensureNotCancelled();
  807. const svgGfx = new _pdf.SVGGraphics(pdfPage.commonObjs, pdfPage.objs);
  808. return svgGfx.getSVG(opList, actualSizeViewport).then(svg => {
  809. ensureNotCancelled();
  810. this.svg = svg;
  811. this.paintedViewportMap.set(svg, actualSizeViewport);
  812. svg.style.width = wrapper.style.width;
  813. svg.style.height = wrapper.style.height;
  814. this.renderingState = _ui_utils.RenderingStates.FINISHED;
  815. wrapper.append(svg);
  816. });
  817. });
  818. return {
  819. promise,
  820. onRenderContinue(cont) {
  821. cont();
  822. },
  823. cancel() {
  824. cancelled = true;
  825. },
  826. get separateAnnots() {
  827. return false;
  828. }
  829. };
  830. }
  831. setPageLabel(label) {
  832. this.pageLabel = typeof label === "string" ? label : null;
  833. if (this.pageLabel !== null) {
  834. this.div.setAttribute("data-page-label", this.pageLabel);
  835. } else {
  836. this.div.removeAttribute("data-page-label");
  837. }
  838. }
  839. get thumbnailCanvas() {
  840. const {
  841. initialOptionalContent,
  842. regularAnnotations
  843. } = this.#useThumbnailCanvas;
  844. return initialOptionalContent && regularAnnotations ? this.canvas : null;
  845. }
  846. }
  847. exports.PDFPageView = PDFPageView;