| /** |
| * @licstart The following is the entire license notice for the |
| * Javascript code in this page |
| * |
| * Copyright 2020 Mozilla Foundation |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| * @licend The above is the entire license notice for the |
| * Javascript code in this page |
| */ |
| "use strict"; |
| |
| Object.defineProperty(exports, "__esModule", { |
| value: true |
| }); |
| exports.PDFPrintService = PDFPrintService; |
| |
| var _ui_utils = require("./ui_utils.js"); |
| |
| var _app = require("./app.js"); |
| |
| var _viewer_compatibility = require("./viewer_compatibility.js"); |
| |
| let activeService = null; |
| let overlayManager = null; |
| |
| function renderPage(activeServiceOnEntry, pdfDocument, pageNumber, size, printResolution, optionalContentConfigPromise) { |
| const scratchCanvas = activeService.scratchCanvas; |
| const PRINT_UNITS = printResolution / 72.0; |
| scratchCanvas.width = Math.floor(size.width * PRINT_UNITS); |
| scratchCanvas.height = Math.floor(size.height * PRINT_UNITS); |
| const width = Math.floor(size.width * _ui_utils.CSS_UNITS) + "px"; |
| const height = Math.floor(size.height * _ui_utils.CSS_UNITS) + "px"; |
| const ctx = scratchCanvas.getContext("2d"); |
| ctx.save(); |
| ctx.fillStyle = "rgb(255, 255, 255)"; |
| ctx.fillRect(0, 0, scratchCanvas.width, scratchCanvas.height); |
| ctx.restore(); |
| return pdfDocument.getPage(pageNumber).then(function (pdfPage) { |
| const renderContext = { |
| canvasContext: ctx, |
| transform: [PRINT_UNITS, 0, 0, PRINT_UNITS, 0, 0], |
| viewport: pdfPage.getViewport({ |
| scale: 1, |
| rotation: size.rotation |
| }), |
| intent: "print", |
| annotationStorage: pdfDocument.annotationStorage, |
| optionalContentConfigPromise |
| }; |
| return pdfPage.render(renderContext).promise; |
| }).then(function () { |
| return { |
| width, |
| height |
| }; |
| }); |
| } |
| |
| function PDFPrintService(pdfDocument, pagesOverview, printContainer, printResolution, optionalContentConfigPromise = null, l10n) { |
| this.pdfDocument = pdfDocument; |
| this.pagesOverview = pagesOverview; |
| this.printContainer = printContainer; |
| this._printResolution = printResolution || 150; |
| this._optionalContentConfigPromise = optionalContentConfigPromise || pdfDocument.getOptionalContentConfig(); |
| this.l10n = l10n || _ui_utils.NullL10n; |
| this.currentPage = -1; |
| this.scratchCanvas = document.createElement("canvas"); |
| } |
| |
| PDFPrintService.prototype = { |
| layout() { |
| this.throwIfInactive(); |
| const body = document.querySelector("body"); |
| body.setAttribute("data-pdfjsprinting", true); |
| const hasEqualPageSizes = this.pagesOverview.every(function (size) { |
| return size.width === this.pagesOverview[0].width && size.height === this.pagesOverview[0].height; |
| }, this); |
| |
| if (!hasEqualPageSizes) { |
| console.warn("Not all pages have the same size. The printed " + "result may be incorrect!"); |
| } |
| |
| this.pageStyleSheet = document.createElement("style"); |
| const pageSize = this.pagesOverview[0]; |
| this.pageStyleSheet.textContent = "@supports ((size:A4) and (size:1pt 1pt)) {" + "@page { size: " + pageSize.width + "pt " + pageSize.height + "pt;}" + "}"; |
| body.appendChild(this.pageStyleSheet); |
| }, |
| |
| destroy() { |
| if (activeService !== this) { |
| return; |
| } |
| |
| this.printContainer.textContent = ""; |
| const body = document.querySelector("body"); |
| body.removeAttribute("data-pdfjsprinting"); |
| |
| if (this.pageStyleSheet) { |
| this.pageStyleSheet.remove(); |
| this.pageStyleSheet = null; |
| } |
| |
| this.scratchCanvas.width = this.scratchCanvas.height = 0; |
| this.scratchCanvas = null; |
| activeService = null; |
| ensureOverlay().then(function () { |
| if (overlayManager.active !== "printServiceOverlay") { |
| return; |
| } |
| |
| overlayManager.close("printServiceOverlay"); |
| }); |
| }, |
| |
| renderPages() { |
| const pageCount = this.pagesOverview.length; |
| |
| const renderNextPage = (resolve, reject) => { |
| this.throwIfInactive(); |
| |
| if (++this.currentPage >= pageCount) { |
| renderProgress(pageCount, pageCount, this.l10n); |
| resolve(); |
| return; |
| } |
| |
| const index = this.currentPage; |
| renderProgress(index, pageCount, this.l10n); |
| renderPage(this, this.pdfDocument, index + 1, this.pagesOverview[index], this._printResolution, this._optionalContentConfigPromise).then(this.useRenderedPage.bind(this)).then(function () { |
| renderNextPage(resolve, reject); |
| }, reject); |
| }; |
| |
| return new Promise(renderNextPage); |
| }, |
| |
| useRenderedPage(printItem) { |
| this.throwIfInactive(); |
| const img = document.createElement("img"); |
| img.style.width = printItem.width; |
| img.style.height = printItem.height; |
| const scratchCanvas = this.scratchCanvas; |
| |
| if ("toBlob" in scratchCanvas && !_viewer_compatibility.viewerCompatibilityParams.disableCreateObjectURL) { |
| scratchCanvas.toBlob(function (blob) { |
| img.src = URL.createObjectURL(blob); |
| }); |
| } else { |
| img.src = scratchCanvas.toDataURL(); |
| } |
| |
| const wrapper = document.createElement("div"); |
| wrapper.appendChild(img); |
| this.printContainer.appendChild(wrapper); |
| return new Promise(function (resolve, reject) { |
| img.onload = resolve; |
| img.onerror = reject; |
| }); |
| }, |
| |
| performPrint() { |
| this.throwIfInactive(); |
| return new Promise(resolve => { |
| setTimeout(() => { |
| if (!this.active) { |
| resolve(); |
| return; |
| } |
| |
| print.call(window); |
| setTimeout(resolve, 20); |
| }, 0); |
| }); |
| }, |
| |
| get active() { |
| return this === activeService; |
| }, |
| |
| throwIfInactive() { |
| if (!this.active) { |
| throw new Error("This print request was cancelled or completed."); |
| } |
| } |
| |
| }; |
| const print = window.print; |
| |
| window.print = function () { |
| if (activeService) { |
| console.warn("Ignored window.print() because of a pending print job."); |
| return; |
| } |
| |
| ensureOverlay().then(function () { |
| if (activeService) { |
| overlayManager.open("printServiceOverlay"); |
| } |
| }); |
| |
| try { |
| dispatchEvent("beforeprint"); |
| } finally { |
| if (!activeService) { |
| console.error("Expected print service to be initialized."); |
| ensureOverlay().then(function () { |
| if (overlayManager.active === "printServiceOverlay") { |
| overlayManager.close("printServiceOverlay"); |
| } |
| }); |
| return; |
| } |
| |
| const activeServiceOnEntry = activeService; |
| activeService.renderPages().then(function () { |
| return activeServiceOnEntry.performPrint(); |
| }).catch(function () {}).then(function () { |
| if (activeServiceOnEntry.active) { |
| abort(); |
| } |
| }); |
| } |
| }; |
| |
| function dispatchEvent(eventType) { |
| const event = document.createEvent("CustomEvent"); |
| event.initCustomEvent(eventType, false, false, "custom"); |
| window.dispatchEvent(event); |
| } |
| |
| function abort() { |
| if (activeService) { |
| activeService.destroy(); |
| dispatchEvent("afterprint"); |
| } |
| } |
| |
| function renderProgress(index, total, l10n) { |
| const progressContainer = document.getElementById("printServiceOverlay"); |
| const progress = Math.round(100 * index / total); |
| const progressBar = progressContainer.querySelector("progress"); |
| const progressPerc = progressContainer.querySelector(".relative-progress"); |
| progressBar.value = progress; |
| l10n.get("print_progress_percent", { |
| progress |
| }, progress + "%").then(msg => { |
| progressPerc.textContent = msg; |
| }); |
| } |
| |
| window.addEventListener("keydown", function (event) { |
| if (event.keyCode === 80 && (event.ctrlKey || event.metaKey) && !event.altKey && (!event.shiftKey || window.chrome || window.opera)) { |
| window.print(); |
| event.preventDefault(); |
| |
| if (event.stopImmediatePropagation) { |
| event.stopImmediatePropagation(); |
| } else { |
| event.stopPropagation(); |
| } |
| } |
| }, true); |
| |
| if ("onbeforeprint" in window) { |
| const stopPropagationIfNeeded = function (event) { |
| if (event.detail !== "custom" && event.stopImmediatePropagation) { |
| event.stopImmediatePropagation(); |
| } |
| }; |
| |
| window.addEventListener("beforeprint", stopPropagationIfNeeded); |
| window.addEventListener("afterprint", stopPropagationIfNeeded); |
| } |
| |
| let overlayPromise; |
| |
| function ensureOverlay() { |
| if (!overlayPromise) { |
| overlayManager = _app.PDFViewerApplication.overlayManager; |
| |
| if (!overlayManager) { |
| throw new Error("The overlay manager has not yet been initialized."); |
| } |
| |
| overlayPromise = overlayManager.register("printServiceOverlay", document.getElementById("printServiceOverlay"), abort, true); |
| document.getElementById("printCancel").onclick = abort; |
| } |
| |
| return overlayPromise; |
| } |
| |
| _app.PDFPrintServiceFactory.instance = { |
| supportsPrinting: true, |
| |
| createPrintService(pdfDocument, pagesOverview, printContainer, printResolution, optionalContentConfigPromise, l10n) { |
| if (activeService) { |
| throw new Error("The print service is created and active."); |
| } |
| |
| activeService = new PDFPrintService(pdfDocument, pagesOverview, printContainer, printResolution, optionalContentConfigPromise, l10n); |
| return activeService; |
| } |
| |
| }; |