| /** |
| * @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.addLinkAttributes = addLinkAttributes; |
| exports.getFilenameFromUrl = getFilenameFromUrl; |
| exports.isFetchSupported = isFetchSupported; |
| exports.isValidFetchUrl = isValidFetchUrl; |
| exports.loadScript = loadScript; |
| exports.deprecated = deprecated; |
| exports.PDFDateString = exports.StatTimer = exports.DOMSVGFactory = exports.DOMCMapReaderFactory = exports.BaseCMapReaderFactory = exports.DOMCanvasFactory = exports.BaseCanvasFactory = exports.DEFAULT_LINK_REL = exports.LinkTarget = exports.RenderingCancelledException = exports.PageViewport = void 0; |
| |
| var _util = require("../shared/util.js"); |
| |
| const DEFAULT_LINK_REL = "noopener noreferrer nofollow"; |
| exports.DEFAULT_LINK_REL = DEFAULT_LINK_REL; |
| const SVG_NS = "http://www.w3.org/2000/svg"; |
| |
| class BaseCanvasFactory { |
| constructor() { |
| if (this.constructor === BaseCanvasFactory) { |
| (0, _util.unreachable)("Cannot initialize BaseCanvasFactory."); |
| } |
| } |
| |
| create(width, height) { |
| (0, _util.unreachable)("Abstract method `create` called."); |
| } |
| |
| reset(canvasAndContext, width, height) { |
| if (!canvasAndContext.canvas) { |
| throw new Error("Canvas is not specified"); |
| } |
| |
| if (width <= 0 || height <= 0) { |
| throw new Error("Invalid canvas size"); |
| } |
| |
| canvasAndContext.canvas.width = width; |
| canvasAndContext.canvas.height = height; |
| } |
| |
| destroy(canvasAndContext) { |
| if (!canvasAndContext.canvas) { |
| throw new Error("Canvas is not specified"); |
| } |
| |
| canvasAndContext.canvas.width = 0; |
| canvasAndContext.canvas.height = 0; |
| canvasAndContext.canvas = null; |
| canvasAndContext.context = null; |
| } |
| |
| } |
| |
| exports.BaseCanvasFactory = BaseCanvasFactory; |
| |
| class DOMCanvasFactory extends BaseCanvasFactory { |
| constructor({ |
| ownerDocument = globalThis.document |
| } = {}) { |
| super(); |
| this._document = ownerDocument; |
| } |
| |
| create(width, height) { |
| if (width <= 0 || height <= 0) { |
| throw new Error("Invalid canvas size"); |
| } |
| |
| const canvas = this._document.createElement("canvas"); |
| |
| const context = canvas.getContext("2d"); |
| canvas.width = width; |
| canvas.height = height; |
| return { |
| canvas, |
| context |
| }; |
| } |
| |
| } |
| |
| exports.DOMCanvasFactory = DOMCanvasFactory; |
| |
| class BaseCMapReaderFactory { |
| constructor({ |
| baseUrl = null, |
| isCompressed = false |
| }) { |
| if (this.constructor === BaseCMapReaderFactory) { |
| (0, _util.unreachable)("Cannot initialize BaseCMapReaderFactory."); |
| } |
| |
| this.baseUrl = baseUrl; |
| this.isCompressed = isCompressed; |
| } |
| |
| async fetch({ |
| name |
| }) { |
| if (!this.baseUrl) { |
| throw new Error('The CMap "baseUrl" parameter must be specified, ensure that ' + 'the "cMapUrl" and "cMapPacked" API parameters are provided.'); |
| } |
| |
| if (!name) { |
| throw new Error("CMap name must be specified."); |
| } |
| |
| const url = this.baseUrl + name + (this.isCompressed ? ".bcmap" : ""); |
| const compressionType = this.isCompressed ? _util.CMapCompressionType.BINARY : _util.CMapCompressionType.NONE; |
| return this._fetchData(url, compressionType).catch(reason => { |
| throw new Error(`Unable to load ${this.isCompressed ? "binary " : ""}CMap at: ${url}`); |
| }); |
| } |
| |
| _fetchData(url, compressionType) { |
| (0, _util.unreachable)("Abstract method `_fetchData` called."); |
| } |
| |
| } |
| |
| exports.BaseCMapReaderFactory = BaseCMapReaderFactory; |
| |
| class DOMCMapReaderFactory extends BaseCMapReaderFactory { |
| _fetchData(url, compressionType) { |
| if (isFetchSupported() && isValidFetchUrl(url, document.baseURI)) { |
| return fetch(url).then(async response => { |
| if (!response.ok) { |
| throw new Error(response.statusText); |
| } |
| |
| let cMapData; |
| |
| if (this.isCompressed) { |
| cMapData = new Uint8Array(await response.arrayBuffer()); |
| } else { |
| cMapData = (0, _util.stringToBytes)(await response.text()); |
| } |
| |
| return { |
| cMapData, |
| compressionType |
| }; |
| }); |
| } |
| |
| return new Promise((resolve, reject) => { |
| const request = new XMLHttpRequest(); |
| request.open("GET", url, true); |
| |
| if (this.isCompressed) { |
| request.responseType = "arraybuffer"; |
| } |
| |
| request.onreadystatechange = () => { |
| if (request.readyState !== XMLHttpRequest.DONE) { |
| return; |
| } |
| |
| if (request.status === 200 || request.status === 0) { |
| let cMapData; |
| |
| if (this.isCompressed && request.response) { |
| cMapData = new Uint8Array(request.response); |
| } else if (!this.isCompressed && request.responseText) { |
| cMapData = (0, _util.stringToBytes)(request.responseText); |
| } |
| |
| if (cMapData) { |
| resolve({ |
| cMapData, |
| compressionType |
| }); |
| return; |
| } |
| } |
| |
| reject(new Error(request.statusText)); |
| }; |
| |
| request.send(null); |
| }); |
| } |
| |
| } |
| |
| exports.DOMCMapReaderFactory = DOMCMapReaderFactory; |
| |
| class DOMSVGFactory { |
| create(width, height) { |
| (0, _util.assert)(width > 0 && height > 0, "Invalid SVG dimensions"); |
| const svg = document.createElementNS(SVG_NS, "svg:svg"); |
| svg.setAttribute("version", "1.1"); |
| svg.setAttribute("width", width + "px"); |
| svg.setAttribute("height", height + "px"); |
| svg.setAttribute("preserveAspectRatio", "none"); |
| svg.setAttribute("viewBox", "0 0 " + width + " " + height); |
| return svg; |
| } |
| |
| createElement(type) { |
| (0, _util.assert)(typeof type === "string", "Invalid SVG element type"); |
| return document.createElementNS(SVG_NS, type); |
| } |
| |
| } |
| |
| exports.DOMSVGFactory = DOMSVGFactory; |
| |
| class PageViewport { |
| constructor({ |
| viewBox, |
| scale, |
| rotation, |
| offsetX = 0, |
| offsetY = 0, |
| dontFlip = false |
| }) { |
| this.viewBox = viewBox; |
| this.scale = scale; |
| this.rotation = rotation; |
| this.offsetX = offsetX; |
| this.offsetY = offsetY; |
| const centerX = (viewBox[2] + viewBox[0]) / 2; |
| const centerY = (viewBox[3] + viewBox[1]) / 2; |
| let rotateA, rotateB, rotateC, rotateD; |
| rotation = rotation % 360; |
| rotation = rotation < 0 ? rotation + 360 : rotation; |
| |
| switch (rotation) { |
| case 180: |
| rotateA = -1; |
| rotateB = 0; |
| rotateC = 0; |
| rotateD = 1; |
| break; |
| |
| case 90: |
| rotateA = 0; |
| rotateB = 1; |
| rotateC = 1; |
| rotateD = 0; |
| break; |
| |
| case 270: |
| rotateA = 0; |
| rotateB = -1; |
| rotateC = -1; |
| rotateD = 0; |
| break; |
| |
| case 0: |
| rotateA = 1; |
| rotateB = 0; |
| rotateC = 0; |
| rotateD = -1; |
| break; |
| |
| default: |
| throw new Error("PageViewport: Invalid rotation, must be a multiple of 90 degrees."); |
| } |
| |
| if (dontFlip) { |
| rotateC = -rotateC; |
| rotateD = -rotateD; |
| } |
| |
| let offsetCanvasX, offsetCanvasY; |
| let width, height; |
| |
| if (rotateA === 0) { |
| offsetCanvasX = Math.abs(centerY - viewBox[1]) * scale + offsetX; |
| offsetCanvasY = Math.abs(centerX - viewBox[0]) * scale + offsetY; |
| width = Math.abs(viewBox[3] - viewBox[1]) * scale; |
| height = Math.abs(viewBox[2] - viewBox[0]) * scale; |
| } else { |
| offsetCanvasX = Math.abs(centerX - viewBox[0]) * scale + offsetX; |
| offsetCanvasY = Math.abs(centerY - viewBox[1]) * scale + offsetY; |
| width = Math.abs(viewBox[2] - viewBox[0]) * scale; |
| height = Math.abs(viewBox[3] - viewBox[1]) * scale; |
| } |
| |
| this.transform = [rotateA * scale, rotateB * scale, rotateC * scale, rotateD * scale, offsetCanvasX - rotateA * scale * centerX - rotateC * scale * centerY, offsetCanvasY - rotateB * scale * centerX - rotateD * scale * centerY]; |
| this.width = width; |
| this.height = height; |
| } |
| |
| clone({ |
| scale = this.scale, |
| rotation = this.rotation, |
| offsetX = this.offsetX, |
| offsetY = this.offsetY, |
| dontFlip = false |
| } = {}) { |
| return new PageViewport({ |
| viewBox: this.viewBox.slice(), |
| scale, |
| rotation, |
| offsetX, |
| offsetY, |
| dontFlip |
| }); |
| } |
| |
| convertToViewportPoint(x, y) { |
| return _util.Util.applyTransform([x, y], this.transform); |
| } |
| |
| convertToViewportRectangle(rect) { |
| const topLeft = _util.Util.applyTransform([rect[0], rect[1]], this.transform); |
| |
| const bottomRight = _util.Util.applyTransform([rect[2], rect[3]], this.transform); |
| |
| return [topLeft[0], topLeft[1], bottomRight[0], bottomRight[1]]; |
| } |
| |
| convertToPdfPoint(x, y) { |
| return _util.Util.applyInverseTransform([x, y], this.transform); |
| } |
| |
| } |
| |
| exports.PageViewport = PageViewport; |
| |
| class RenderingCancelledException extends _util.BaseException { |
| constructor(msg, type) { |
| super(msg); |
| this.type = type; |
| } |
| |
| } |
| |
| exports.RenderingCancelledException = RenderingCancelledException; |
| const LinkTarget = { |
| NONE: 0, |
| SELF: 1, |
| BLANK: 2, |
| PARENT: 3, |
| TOP: 4 |
| }; |
| exports.LinkTarget = LinkTarget; |
| |
| function addLinkAttributes(link, { |
| url, |
| target, |
| rel, |
| enabled = true |
| } = {}) { |
| (0, _util.assert)(url && typeof url === "string", 'addLinkAttributes: A valid "url" parameter must provided.'); |
| const urlNullRemoved = (0, _util.removeNullCharacters)(url); |
| |
| if (enabled) { |
| link.href = link.title = urlNullRemoved; |
| } else { |
| link.href = ""; |
| link.title = `Disabled: ${urlNullRemoved}`; |
| |
| link.onclick = () => { |
| return false; |
| }; |
| } |
| |
| let targetStr = ""; |
| |
| switch (target) { |
| case LinkTarget.NONE: |
| break; |
| |
| case LinkTarget.SELF: |
| targetStr = "_self"; |
| break; |
| |
| case LinkTarget.BLANK: |
| targetStr = "_blank"; |
| break; |
| |
| case LinkTarget.PARENT: |
| targetStr = "_parent"; |
| break; |
| |
| case LinkTarget.TOP: |
| targetStr = "_top"; |
| break; |
| } |
| |
| link.target = targetStr; |
| link.rel = typeof rel === "string" ? rel : DEFAULT_LINK_REL; |
| } |
| |
| function getFilenameFromUrl(url) { |
| const anchor = url.indexOf("#"); |
| const query = url.indexOf("?"); |
| const end = Math.min(anchor > 0 ? anchor : url.length, query > 0 ? query : url.length); |
| return url.substring(url.lastIndexOf("/", end) + 1, end); |
| } |
| |
| class StatTimer { |
| constructor() { |
| this.started = Object.create(null); |
| this.times = []; |
| } |
| |
| time(name) { |
| if (name in this.started) { |
| (0, _util.warn)(`Timer is already running for ${name}`); |
| } |
| |
| this.started[name] = Date.now(); |
| } |
| |
| timeEnd(name) { |
| if (!(name in this.started)) { |
| (0, _util.warn)(`Timer has not been started for ${name}`); |
| } |
| |
| this.times.push({ |
| name, |
| start: this.started[name], |
| end: Date.now() |
| }); |
| delete this.started[name]; |
| } |
| |
| toString() { |
| const outBuf = []; |
| let longest = 0; |
| |
| for (const time of this.times) { |
| const name = time.name; |
| |
| if (name.length > longest) { |
| longest = name.length; |
| } |
| } |
| |
| for (const time of this.times) { |
| const duration = time.end - time.start; |
| outBuf.push(`${time.name.padEnd(longest)} ${duration}ms\n`); |
| } |
| |
| return outBuf.join(""); |
| } |
| |
| } |
| |
| exports.StatTimer = StatTimer; |
| |
| function isFetchSupported() { |
| return typeof fetch !== "undefined" && typeof Response !== "undefined" && "body" in Response.prototype && typeof ReadableStream !== "undefined"; |
| } |
| |
| function isValidFetchUrl(url, baseUrl) { |
| try { |
| const { |
| protocol |
| } = baseUrl ? new URL(url, baseUrl) : new URL(url); |
| return protocol === "http:" || protocol === "https:"; |
| } catch (ex) { |
| return false; |
| } |
| } |
| |
| function loadScript(src) { |
| return new Promise((resolve, reject) => { |
| const script = document.createElement("script"); |
| script.src = src; |
| script.onload = resolve; |
| |
| script.onerror = function () { |
| reject(new Error(`Cannot load script at: ${script.src}`)); |
| }; |
| |
| (document.head || document.documentElement).appendChild(script); |
| }); |
| } |
| |
| function deprecated(details) { |
| console.log("Deprecated API usage: " + details); |
| } |
| |
| let pdfDateStringRegex; |
| |
| class PDFDateString { |
| static toDateObject(input) { |
| if (!input || !(0, _util.isString)(input)) { |
| return null; |
| } |
| |
| if (!pdfDateStringRegex) { |
| pdfDateStringRegex = new RegExp("^D:" + "(\\d{4})" + "(\\d{2})?" + "(\\d{2})?" + "(\\d{2})?" + "(\\d{2})?" + "(\\d{2})?" + "([Z|+|-])?" + "(\\d{2})?" + "'?" + "(\\d{2})?" + "'?"); |
| } |
| |
| const matches = pdfDateStringRegex.exec(input); |
| |
| if (!matches) { |
| return null; |
| } |
| |
| const year = parseInt(matches[1], 10); |
| let month = parseInt(matches[2], 10); |
| month = month >= 1 && month <= 12 ? month - 1 : 0; |
| let day = parseInt(matches[3], 10); |
| day = day >= 1 && day <= 31 ? day : 1; |
| let hour = parseInt(matches[4], 10); |
| hour = hour >= 0 && hour <= 23 ? hour : 0; |
| let minute = parseInt(matches[5], 10); |
| minute = minute >= 0 && minute <= 59 ? minute : 0; |
| let second = parseInt(matches[6], 10); |
| second = second >= 0 && second <= 59 ? second : 0; |
| const universalTimeRelation = matches[7] || "Z"; |
| let offsetHour = parseInt(matches[8], 10); |
| offsetHour = offsetHour >= 0 && offsetHour <= 23 ? offsetHour : 0; |
| let offsetMinute = parseInt(matches[9], 10) || 0; |
| offsetMinute = offsetMinute >= 0 && offsetMinute <= 59 ? offsetMinute : 0; |
| |
| if (universalTimeRelation === "-") { |
| hour += offsetHour; |
| minute += offsetMinute; |
| } else if (universalTimeRelation === "+") { |
| hour -= offsetHour; |
| minute -= offsetMinute; |
| } |
| |
| return new Date(Date.UTC(year, month, day, hour, minute, second)); |
| } |
| |
| } |
| |
| exports.PDFDateString = PDFDateString; |