diff --git a/toolkit/components/pdfjs/content/build/pdf.mjs b/toolkit/components/pdfjs/content/build/pdf.mjs --- a/toolkit/components/pdfjs/content/build/pdf.mjs +++ b/toolkit/components/pdfjs/content/build/pdf.mjs @@ -53,16 +53,18 @@ AnnotationEditorUIManager: () => (/* reexport */ AnnotationEditorUIManager), AnnotationLayer: () => (/* reexport */ AnnotationLayer), AnnotationMode: () => (/* reexport */ AnnotationMode), CMapCompressionType: () => (/* reexport */ CMapCompressionType), DOMSVGFactory: () => (/* reexport */ DOMSVGFactory), + DrawLayer: () => (/* reexport */ DrawLayer), FeatureTest: () => (/* reexport */ util_FeatureTest), GlobalWorkerOptions: () => (/* reexport */ GlobalWorkerOptions), ImageKind: () => (/* reexport */ util_ImageKind), InvalidPDFException: () => (/* reexport */ InvalidPDFException), MissingPDFException: () => (/* reexport */ MissingPDFException), OPS: () => (/* reexport */ OPS), + Outliner: () => (/* reexport */ Outliner), PDFDataRangeTransport: () => (/* reexport */ PDFDataRangeTransport), PDFDateString: () => (/* reexport */ PDFDateString), PDFWorker: () => (/* reexport */ PDFWorker), PasswordResponses: () => (/* reexport */ PasswordResponses), PermissionFlag: () => (/* reexport */ PermissionFlag), @@ -118,10 +120,11 @@ const AnnotationEditorPrefix = "pdfjs_internal_editor_"; const AnnotationEditorType = { DISABLE: -1, NONE: 0, FREETEXT: 3, + HIGHLIGHT: 9, STAMP: 13, INK: 15 }; const AnnotationEditorParamsType = { RESIZE: 1, @@ -729,30 +732,45 @@ function stringToPDFString(str) { if (str[0] >= "\xEF") { let encoding; if (str[0] === "\xFE" && str[1] === "\xFF") { encoding = "utf-16be"; + if (str.length % 2 === 1) { + str = str.slice(0, -1); + } } else if (str[0] === "\xFF" && str[1] === "\xFE") { encoding = "utf-16le"; + if (str.length % 2 === 1) { + str = str.slice(0, -1); + } } else if (str[0] === "\xEF" && str[1] === "\xBB" && str[2] === "\xBF") { encoding = "utf-8"; } if (encoding) { try { const decoder = new TextDecoder(encoding, { fatal: true }); const buffer = stringToBytes(str); - return decoder.decode(buffer); + const decoded = decoder.decode(buffer); + if (!decoded.includes("\x1b")) { + return decoded; + } + return decoded.replaceAll(/\x1b[^\x1b]*(?:\x1b|$)/g, ""); } catch (ex) { warn(`stringToPDFString: "${ex}".`); } } } const strBuf = []; for (let i = 0, ii = str.length; i < ii; i++) { - const code = PDFStringTranslateTable[str.charCodeAt(i)]; + const charCode = str.charCodeAt(i); + if (charCode === 0x1b) { + while (++i < ii && str.charCodeAt(i) !== 0x1b) {} + continue; + } + const code = PDFStringTranslateTable[charCode]; strBuf.push(code ? String.fromCharCode(code) : str.charAt(i)); } return strBuf.join(""); } function stringToUTF8String(str) { @@ -1209,10 +1227,12 @@ throw new Error(response.statusText); } switch (type) { case "arraybuffer": return response.arrayBuffer(); + case "blob": + return response.blob(); case "json": return response.json(); } return response.text(); } @@ -1616,15 +1636,11 @@ isSvg: false }; let image; if (typeof rawData === "string") { data.url = rawData; - const response = await fetch(rawData); - if (!response.ok) { - throw new Error(response.statusText); - } - image = await response.blob(); + image = await fetchData(rawData, "blob"); } else { image = data.file = rawData; } if (image.type === "image/svg+xml") { const mustRemoveAspectRatioPromise = ImageManager._isSVGFittingCanvas; @@ -2589,11 +2605,13 @@ this.#selectEditors(this.#allEditors.values()); } unselectAll() { if (this.#activeEditor) { this.#activeEditor.commitOrRemove(); - return; + if (this.#mode !== AnnotationEditorType.NONE) { + return; + } } if (!this.hasSelection) { return; } for (const editor of this.#selectedEditors) { @@ -8153,11 +8171,11 @@ worker = workerParams.port ? PDFWorker.fromPort(workerParams) : new PDFWorker(workerParams); task._worker = worker; } const fetchDocParams = { docId, - apiVersion: '4.0.240', + apiVersion: '4.0.275', data, password, disableAutoFetch, rangeChunkSize, length, @@ -9777,12 +9795,12 @@ this.callback(); } } } } -const version = '4.0.240'; -const build = 'ffbfd680e'; +const version = '4.0.275'; +const build = '4bf7ff202'; ;// CONCATENATED MODULE: ./src/display/text_layer.js const MAX_TEXT_DIVS_TO_RENDER = 100000; @@ -11711,10 +11729,17 @@ value = value !== data.buttonValue; storage.setValue(id, { value }); } + if (value) { + for (const radio of this._getElementsByName(data.fieldName, id)) { + storage.setValue(radio.id, { + value: false + }); + } + } const element = document.createElement("input"); GetElementsByNameSet.add(element); element.setAttribute("data-element-id", id); element.disabled = data.readOnly; this._setRequired(element, this.data.required); @@ -13738,12 +13763,14 @@ if (event.button !== 0 || !this.isInEditMode() || this.#disableEditing) { return; } this.setInForeground(); event.preventDefault(); - if (event.type !== "mouse") { - this.div.focus(); + if (event.pointerType !== "mouse" && !this.div.contains(document.activeElement)) { + this.div.focus({ + preventScroll: true + }); } this.#startDrawing(event.offsetX, event.offsetY); } canvasPointermove(event) { event.preventDefault(); @@ -14557,11 +14584,11 @@ } this.div.hidden = false; } } addInkEditorIfNeeded(isCommitting) { - if (!isCommitting && this.#uiManager.getMode() !== AnnotationEditorType.INK) { + if (this.#uiManager.getMode() !== AnnotationEditorType.INK) { return; } if (!isCommitting) { for (const editor of this.#editors.values()) { if (editor.isEmpty()) { @@ -14953,38 +14980,395 @@ } = this.viewport.rawDims; return [pageWidth, pageHeight]; } } +;// CONCATENATED MODULE: ./src/display/draw_layer.js + + +class DrawLayer { + #parent = null; + #id = 0; + #mapping = new Map(); + constructor({ + pageIndex + }) { + this.pageIndex = pageIndex; + } + setParent(parent) { + if (!this.#parent) { + this.#parent = parent; + return; + } + if (this.#parent !== parent) { + if (this.#mapping.size > 0) { + for (const root of this.#mapping.values()) { + root.remove(); + parent.append(root); + } + } + this.#parent = parent; + } + } + static get _svgFactory() { + return shadow(this, "_svgFactory", new DOMSVGFactory()); + } + static #setBox(element, { + x, + y, + width, + height + }) { + const { + style + } = element; + style.top = `${100 * y}%`; + style.left = `${100 * x}%`; + style.width = `${100 * width}%`; + style.height = `${100 * height}%`; + } + #createSVG(box) { + const svg = DrawLayer._svgFactory.create(1, 1, true); + this.#parent.append(svg); + DrawLayer.#setBox(svg, box); + return svg; + } + highlight({ + outlines, + box + }, color, opacity) { + const id = this.#id++; + const root = this.#createSVG(box); + root.classList.add("highlight"); + const defs = DrawLayer._svgFactory.createElement("defs"); + root.append(defs); + const path = DrawLayer._svgFactory.createElement("path"); + defs.append(path); + const pathId = `path_p${this.pageIndex}_${id}`; + path.setAttribute("id", pathId); + path.setAttribute("d", DrawLayer.#extractPathFromHighlightOutlines(outlines)); + const clipPath = DrawLayer._svgFactory.createElement("clipPath"); + defs.append(clipPath); + const clipPathId = `clip_${pathId}`; + clipPath.setAttribute("id", clipPathId); + clipPath.setAttribute("clipPathUnits", "objectBoundingBox"); + const clipPathUse = DrawLayer._svgFactory.createElement("use"); + clipPath.append(clipPathUse); + clipPathUse.setAttribute("href", `#${pathId}`); + clipPathUse.classList.add("clip"); + const use = DrawLayer._svgFactory.createElement("use"); + root.append(use); + root.setAttribute("fill", color); + root.setAttribute("fill-opacity", opacity); + use.setAttribute("href", `#${pathId}`); + this.#mapping.set(id, root); + return { + id, + clipPathId: `url(#${clipPathId})` + }; + } + highlightOutline({ + outlines, + box + }) { + const id = this.#id++; + const root = this.#createSVG(box); + root.classList.add("highlightOutline"); + const defs = DrawLayer._svgFactory.createElement("defs"); + root.append(defs); + const path = DrawLayer._svgFactory.createElement("path"); + defs.append(path); + const pathId = `path_p${this.pageIndex}_${id}`; + path.setAttribute("id", pathId); + path.setAttribute("d", DrawLayer.#extractPathFromHighlightOutlines(outlines)); + path.setAttribute("vector-effect", "non-scaling-stroke"); + const use1 = DrawLayer._svgFactory.createElement("use"); + root.append(use1); + use1.setAttribute("href", `#${pathId}`); + const use2 = use1.cloneNode(); + root.append(use2); + use1.classList.add("mainOutline"); + use2.classList.add("secondaryOutline"); + this.#mapping.set(id, root); + return id; + } + static #extractPathFromHighlightOutlines(polygons) { + const buffer = []; + for (const polygon of polygons) { + let [prevX, prevY] = polygon; + buffer.push(`M${prevX} ${prevY}`); + for (let i = 2; i < polygon.length; i += 2) { + const x = polygon[i]; + const y = polygon[i + 1]; + if (x === prevX) { + buffer.push(`V${y}`); + prevY = y; + } else if (y === prevY) { + buffer.push(`H${x}`); + prevX = x; + } + } + buffer.push("Z"); + } + return buffer.join(" "); + } + updateBox(id, box) { + DrawLayer.#setBox(this.#mapping.get(id), box); + } + rotate(id, angle) { + this.#mapping.get(id).setAttribute("data-main-rotation", angle); + } + changeColor(id, color) { + this.#mapping.get(id).setAttribute("fill", color); + } + changeOpacity(id, opacity) { + this.#mapping.get(id).setAttribute("fill-opacity", opacity); + } + addClass(id, className) { + this.#mapping.get(id).classList.add(className); + } + removeClass(id, className) { + this.#mapping.get(id).classList.remove(className); + } + remove(id) { + this.#mapping.get(id).remove(); + this.#mapping.delete(id); + } + destroy() { + this.#parent = null; + for (const root of this.#mapping.values()) { + root.remove(); + } + this.#mapping.clear(); + } +} + +;// CONCATENATED MODULE: ./src/display/editor/outliner.js +class Outliner { + #box; + #verticalEdges = []; + #intervals = []; + constructor(boxes, borderWidth = 0, innerMargin = 0, isLTR = true) { + let minX = Infinity; + let maxX = -Infinity; + let minY = Infinity; + let maxY = -Infinity; + const NUMBER_OF_DIGITS = 4; + const EPSILON = 10 ** -NUMBER_OF_DIGITS; + for (const { + x, + y, + width, + height + } of boxes) { + const x1 = Math.floor((x - borderWidth) / EPSILON) * EPSILON; + const x2 = Math.ceil((x + width + borderWidth) / EPSILON) * EPSILON; + const y1 = Math.floor((y - borderWidth) / EPSILON) * EPSILON; + const y2 = Math.ceil((y + height + borderWidth) / EPSILON) * EPSILON; + const left = [x1, y1, y2, true]; + const right = [x2, y1, y2, false]; + this.#verticalEdges.push(left, right); + minX = Math.min(minX, x1); + maxX = Math.max(maxX, x2); + minY = Math.min(minY, y1); + maxY = Math.max(maxY, y2); + } + const bboxWidth = maxX - minX + 2 * innerMargin; + const bboxHeight = maxY - minY + 2 * innerMargin; + const shiftedMinX = minX - innerMargin; + const shiftedMinY = minY - innerMargin; + const lastEdge = this.#verticalEdges.at(isLTR ? -1 : -2); + const lastPoint = [lastEdge[0], lastEdge[2]]; + for (const edge of this.#verticalEdges) { + const [x, y1, y2] = edge; + edge[0] = (x - shiftedMinX) / bboxWidth; + edge[1] = (y1 - shiftedMinY) / bboxHeight; + edge[2] = (y2 - shiftedMinY) / bboxHeight; + } + this.#box = { + x: shiftedMinX, + y: shiftedMinY, + width: bboxWidth, + height: bboxHeight, + lastPoint + }; + } + getOutlines() { + this.#verticalEdges.sort((a, b) => a[0] - b[0] || a[1] - b[1] || a[2] - b[2]); + const outlineVerticalEdges = []; + for (const edge of this.#verticalEdges) { + if (edge[3]) { + outlineVerticalEdges.push(...this.#breakEdge(edge)); + this.#insert(edge); + } else { + this.#remove(edge); + outlineVerticalEdges.push(...this.#breakEdge(edge)); + } + } + return this.#getOutlines(outlineVerticalEdges); + } + #getOutlines(outlineVerticalEdges) { + const edges = []; + const allEdges = new Set(); + for (const edge of outlineVerticalEdges) { + const [x, y1, y2] = edge; + edges.push([x, y1, edge], [x, y2, edge]); + } + edges.sort((a, b) => a[1] - b[1] || a[0] - b[0]); + for (let i = 0, ii = edges.length; i < ii; i += 2) { + const edge1 = edges[i][2]; + const edge2 = edges[i + 1][2]; + edge1.push(edge2); + edge2.push(edge1); + allEdges.add(edge1); + allEdges.add(edge2); + } + const outlines = []; + let outline; + while (allEdges.size > 0) { + const edge = allEdges.values().next().value; + let [x, y1, y2, edge1, edge2] = edge; + allEdges.delete(edge); + let lastPointX = x; + let lastPointY = y1; + outline = [x, y2]; + outlines.push(outline); + while (true) { + let e; + if (allEdges.has(edge1)) { + e = edge1; + } else if (allEdges.has(edge2)) { + e = edge2; + } else { + break; + } + allEdges.delete(e); + [x, y1, y2, edge1, edge2] = e; + if (lastPointX !== x) { + outline.push(lastPointX, lastPointY, x, lastPointY === y1 ? y1 : y2); + lastPointX = x; + } + lastPointY = lastPointY === y1 ? y2 : y1; + } + outline.push(lastPointX, lastPointY); + } + return { + outlines, + box: this.#box + }; + } + #binarySearch(y) { + const array = this.#intervals; + let start = 0; + let end = array.length - 1; + while (start <= end) { + const middle = start + end >> 1; + const y1 = array[middle][0]; + if (y1 === y) { + return middle; + } + if (y1 < y) { + start = middle + 1; + } else { + end = middle - 1; + } + } + return end + 1; + } + #insert([, y1, y2]) { + const index = this.#binarySearch(y1); + this.#intervals.splice(index, 0, [y1, y2]); + } + #remove([, y1, y2]) { + const index = this.#binarySearch(y1); + for (let i = index; i < this.#intervals.length; i++) { + const [start, end] = this.#intervals[i]; + if (start !== y1) { + break; + } + if (start === y1 && end === y2) { + this.#intervals.splice(i, 1); + return; + } + } + for (let i = index - 1; i >= 0; i--) { + const [start, end] = this.#intervals[i]; + if (start !== y1) { + break; + } + if (start === y1 && end === y2) { + this.#intervals.splice(i, 1); + return; + } + } + } + #breakEdge(edge) { + const [x, y1, y2] = edge; + const results = [[x, y1, y2]]; + const index = this.#binarySearch(y2); + for (let i = 0; i < index; i++) { + const [start, end] = this.#intervals[i]; + for (let j = 0, jj = results.length; j < jj; j++) { + const [, y3, y4] = results[j]; + if (end <= y3 || y4 <= start) { + continue; + } + if (y3 >= start) { + if (y4 > end) { + results[j][1] = end; + } else { + if (jj === 1) { + return []; + } + results.splice(j, 1); + j--; + jj--; + } + continue; + } + results[j][2] = start; + if (y4 > end) { + results.push([x, end, y4]); + } + } + } + return results; + } +} + ;// CONCATENATED MODULE: ./src/pdf.js -const pdfjsVersion = '4.0.240'; -const pdfjsBuild = 'ffbfd680e'; + + +const pdfjsVersion = '4.0.275'; +const pdfjsBuild = '4bf7ff202'; var __webpack_exports__AbortException = __webpack_exports__.AbortException; var __webpack_exports__AnnotationEditorLayer = __webpack_exports__.AnnotationEditorLayer; var __webpack_exports__AnnotationEditorParamsType = __webpack_exports__.AnnotationEditorParamsType; var __webpack_exports__AnnotationEditorType = __webpack_exports__.AnnotationEditorType; var __webpack_exports__AnnotationEditorUIManager = __webpack_exports__.AnnotationEditorUIManager; var __webpack_exports__AnnotationLayer = __webpack_exports__.AnnotationLayer; var __webpack_exports__AnnotationMode = __webpack_exports__.AnnotationMode; var __webpack_exports__CMapCompressionType = __webpack_exports__.CMapCompressionType; var __webpack_exports__DOMSVGFactory = __webpack_exports__.DOMSVGFactory; +var __webpack_exports__DrawLayer = __webpack_exports__.DrawLayer; var __webpack_exports__FeatureTest = __webpack_exports__.FeatureTest; var __webpack_exports__GlobalWorkerOptions = __webpack_exports__.GlobalWorkerOptions; var __webpack_exports__ImageKind = __webpack_exports__.ImageKind; var __webpack_exports__InvalidPDFException = __webpack_exports__.InvalidPDFException; var __webpack_exports__MissingPDFException = __webpack_exports__.MissingPDFException; var __webpack_exports__OPS = __webpack_exports__.OPS; +var __webpack_exports__Outliner = __webpack_exports__.Outliner; var __webpack_exports__PDFDataRangeTransport = __webpack_exports__.PDFDataRangeTransport; var __webpack_exports__PDFDateString = __webpack_exports__.PDFDateString; var __webpack_exports__PDFWorker = __webpack_exports__.PDFWorker; var __webpack_exports__PasswordResponses = __webpack_exports__.PasswordResponses; var __webpack_exports__PermissionFlag = __webpack_exports__.PermissionFlag; @@ -15009,6 +15393,6 @@ var __webpack_exports__renderTextLayer = __webpack_exports__.renderTextLayer; var __webpack_exports__setLayerDimensions = __webpack_exports__.setLayerDimensions; var __webpack_exports__shadow = __webpack_exports__.shadow; var __webpack_exports__updateTextLayer = __webpack_exports__.updateTextLayer; var __webpack_exports__version = __webpack_exports__.version; -export { __webpack_exports__AbortException as AbortException, __webpack_exports__AnnotationEditorLayer as AnnotationEditorLayer, __webpack_exports__AnnotationEditorParamsType as AnnotationEditorParamsType, __webpack_exports__AnnotationEditorType as AnnotationEditorType, __webpack_exports__AnnotationEditorUIManager as AnnotationEditorUIManager, __webpack_exports__AnnotationLayer as AnnotationLayer, __webpack_exports__AnnotationMode as AnnotationMode, __webpack_exports__CMapCompressionType as CMapCompressionType, __webpack_exports__DOMSVGFactory as DOMSVGFactory, __webpack_exports__FeatureTest as FeatureTest, __webpack_exports__GlobalWorkerOptions as GlobalWorkerOptions, __webpack_exports__ImageKind as ImageKind, __webpack_exports__InvalidPDFException as InvalidPDFException, __webpack_exports__MissingPDFException as MissingPDFException, __webpack_exports__OPS as OPS, __webpack_exports__PDFDataRangeTransport as PDFDataRangeTransport, __webpack_exports__PDFDateString as PDFDateString, __webpack_exports__PDFWorker as PDFWorker, __webpack_exports__PasswordResponses as PasswordResponses, __webpack_exports__PermissionFlag as PermissionFlag, __webpack_exports__PixelsPerInch as PixelsPerInch, __webpack_exports__PromiseCapability as PromiseCapability, __webpack_exports__RenderingCancelledException as RenderingCancelledException, __webpack_exports__UnexpectedResponseException as UnexpectedResponseException, __webpack_exports__Util as Util, __webpack_exports__VerbosityLevel as VerbosityLevel, __webpack_exports__XfaLayer as XfaLayer, __webpack_exports__build as build, __webpack_exports__createValidAbsoluteUrl as createValidAbsoluteUrl, __webpack_exports__fetchData as fetchData, __webpack_exports__getDocument as getDocument, __webpack_exports__getFilenameFromUrl as getFilenameFromUrl, __webpack_exports__getPdfFilenameFromUrl as getPdfFilenameFromUrl, __webpack_exports__getXfaPageViewport as getXfaPageViewport, __webpack_exports__isDataScheme as isDataScheme, __webpack_exports__isPdfFile as isPdfFile, __webpack_exports__noContextMenu as noContextMenu, __webpack_exports__normalizeUnicode as normalizeUnicode, __webpack_exports__renderTextLayer as renderTextLayer, __webpack_exports__setLayerDimensions as setLayerDimensions, __webpack_exports__shadow as shadow, __webpack_exports__updateTextLayer as updateTextLayer, __webpack_exports__version as version }; +export { __webpack_exports__AbortException as AbortException, __webpack_exports__AnnotationEditorLayer as AnnotationEditorLayer, __webpack_exports__AnnotationEditorParamsType as AnnotationEditorParamsType, __webpack_exports__AnnotationEditorType as AnnotationEditorType, __webpack_exports__AnnotationEditorUIManager as AnnotationEditorUIManager, __webpack_exports__AnnotationLayer as AnnotationLayer, __webpack_exports__AnnotationMode as AnnotationMode, __webpack_exports__CMapCompressionType as CMapCompressionType, __webpack_exports__DOMSVGFactory as DOMSVGFactory, __webpack_exports__DrawLayer as DrawLayer, __webpack_exports__FeatureTest as FeatureTest, __webpack_exports__GlobalWorkerOptions as GlobalWorkerOptions, __webpack_exports__ImageKind as ImageKind, __webpack_exports__InvalidPDFException as InvalidPDFException, __webpack_exports__MissingPDFException as MissingPDFException, __webpack_exports__OPS as OPS, __webpack_exports__Outliner as Outliner, __webpack_exports__PDFDataRangeTransport as PDFDataRangeTransport, __webpack_exports__PDFDateString as PDFDateString, __webpack_exports__PDFWorker as PDFWorker, __webpack_exports__PasswordResponses as PasswordResponses, __webpack_exports__PermissionFlag as PermissionFlag, __webpack_exports__PixelsPerInch as PixelsPerInch, __webpack_exports__PromiseCapability as PromiseCapability, __webpack_exports__RenderingCancelledException as RenderingCancelledException, __webpack_exports__UnexpectedResponseException as UnexpectedResponseException, __webpack_exports__Util as Util, __webpack_exports__VerbosityLevel as VerbosityLevel, __webpack_exports__XfaLayer as XfaLayer, __webpack_exports__build as build, __webpack_exports__createValidAbsoluteUrl as createValidAbsoluteUrl, __webpack_exports__fetchData as fetchData, __webpack_exports__getDocument as getDocument, __webpack_exports__getFilenameFromUrl as getFilenameFromUrl, __webpack_exports__getPdfFilenameFromUrl as getPdfFilenameFromUrl, __webpack_exports__getXfaPageViewport as getXfaPageViewport, __webpack_exports__isDataScheme as isDataScheme, __webpack_exports__isPdfFile as isPdfFile, __webpack_exports__noContextMenu as noContextMenu, __webpack_exports__normalizeUnicode as normalizeUnicode, __webpack_exports__renderTextLayer as renderTextLayer, __webpack_exports__setLayerDimensions as setLayerDimensions, __webpack_exports__shadow as shadow, __webpack_exports__updateTextLayer as updateTextLayer, __webpack_exports__version as version }; diff --git a/toolkit/components/pdfjs/content/build/pdf.scripting.mjs b/toolkit/components/pdfjs/content/build/pdf.scripting.mjs --- a/toolkit/components/pdfjs/content/build/pdf.scripting.mjs +++ b/toolkit/components/pdfjs/content/build/pdf.scripting.mjs @@ -3994,10 +3994,10 @@ }; } ;// CONCATENATED MODULE: ./src/pdf.scripting.js -const pdfjsVersion = '4.0.240'; -const pdfjsBuild = 'ffbfd680e'; +const pdfjsVersion = '4.0.275'; +const pdfjsBuild = '4bf7ff202'; globalThis.pdfjsScripting = { initSandbox: initSandbox }; diff --git a/toolkit/components/pdfjs/content/build/pdf.worker.mjs b/toolkit/components/pdfjs/content/build/pdf.worker.mjs --- a/toolkit/components/pdfjs/content/build/pdf.worker.mjs +++ b/toolkit/components/pdfjs/content/build/pdf.worker.mjs @@ -76,10 +76,11 @@ const AnnotationEditorPrefix = "pdfjs_internal_editor_"; const AnnotationEditorType = { DISABLE: -1, NONE: 0, FREETEXT: 3, + HIGHLIGHT: 9, STAMP: 13, INK: 15 }; const AnnotationEditorParamsType = { RESIZE: 1, @@ -687,30 +688,45 @@ function stringToPDFString(str) { if (str[0] >= "\xEF") { let encoding; if (str[0] === "\xFE" && str[1] === "\xFF") { encoding = "utf-16be"; + if (str.length % 2 === 1) { + str = str.slice(0, -1); + } } else if (str[0] === "\xFF" && str[1] === "\xFE") { encoding = "utf-16le"; + if (str.length % 2 === 1) { + str = str.slice(0, -1); + } } else if (str[0] === "\xEF" && str[1] === "\xBB" && str[2] === "\xBF") { encoding = "utf-8"; } if (encoding) { try { const decoder = new TextDecoder(encoding, { fatal: true }); const buffer = stringToBytes(str); - return decoder.decode(buffer); + const decoded = decoder.decode(buffer); + if (!decoded.includes("\x1b")) { + return decoded; + } + return decoded.replaceAll(/\x1b[^\x1b]*(?:\x1b|$)/g, ""); } catch (ex) { warn(`stringToPDFString: "${ex}".`); } } } const strBuf = []; for (let i = 0, ii = str.length; i < ii; i++) { - const code = PDFStringTranslateTable[str.charCodeAt(i)]; + const charCode = str.charCodeAt(i); + if (charCode === 0x1b) { + while (++i < ii && str.charCodeAt(i) !== 0x1b) {} + continue; + } + const code = PDFStringTranslateTable[charCode]; strBuf.push(code ? String.fromCharCode(code) : str.charAt(i)); } return strBuf.join(""); } function stringToUTF8String(str) { @@ -3962,10 +3978,14 @@ } } } return [codes, maxLen]; } + #endsStreamOnError(err) { + info(err); + this.eof = true; + } readBlock() { let buffer, len; const str = this.str; let hdr = this.getBits(3); if (hdr & 1) { @@ -3973,23 +3993,27 @@ } hdr >>= 1; if (hdr === 0) { let b; if ((b = str.getByte()) === -1) { - throw new FormatError("Bad block header in flate stream"); + this.#endsStreamOnError("Bad block header in flate stream"); + return; } let blockLen = b; if ((b = str.getByte()) === -1) { - throw new FormatError("Bad block header in flate stream"); + this.#endsStreamOnError("Bad block header in flate stream"); + return; } blockLen |= b << 8; if ((b = str.getByte()) === -1) { - throw new FormatError("Bad block header in flate stream"); + this.#endsStreamOnError("Bad block header in flate stream"); + return; } let check = b; if ((b = str.getByte()) === -1) { - throw new FormatError("Bad block header in flate stream"); + this.#endsStreamOnError("Bad block header in flate stream"); + return; } check |= b << 8; if (check !== (~blockLen & 0xffff) && (blockLen !== 0 || check !== 0)) { throw new FormatError("Bad uncompressed block length in flate stream"); } @@ -7165,10 +7189,13 @@ throw new JpegError("JpegImage.parse - unknown marker: " + fileMarker.toString(16)); } fileMarker = readUint16(data, offset); offset += 2; } + if (!frame) { + throw new JpegError("JpegImage.parse - no frame data found."); + } this.width = frame.samplesPerLine; this.height = frame.scanLines; this.jfif = jfif; this.adobe = adobe; this.components = []; @@ -50576,10 +50603,13 @@ evaluator, task, baseFontRef })); break; + case AnnotationEditorType.HIGHLIGHT: + promises.push(HighlightAnnotation.createNewAnnotation(xref, annotation, dependencies)); + break; case AnnotationEditorType.INK: promises.push(InkAnnotation.createNewAnnotation(xref, annotation, dependencies)); break; case AnnotationEditorType.STAMP: if (!isOffscreenCanvasSupported) { @@ -50640,10 +50670,15 @@ evaluator, task, evaluatorOptions: options })); break; + case AnnotationEditorType.HIGHLIGHT: + promises.push(HighlightAnnotation.createNewPrintAnnotation(annotationGlobals, xref, annotation, { + evaluatorOptions: options + })); + break; case AnnotationEditorType.INK: promises.push(InkAnnotation.createNewPrintAnnotation(annotationGlobals, xref, annotation, { evaluatorOptions: options })); break; @@ -53298,10 +53333,84 @@ } } else { this.data.popupRef = null; } } + static createNewDict(annotation, xref, { + apRef, + ap + }) { + const { + color, + opacity, + rect, + rotation, + user, + quadPoints + } = annotation; + const highlight = new Dict(xref); + highlight.set("Type", Name.get("Annot")); + highlight.set("Subtype", Name.get("Highlight")); + highlight.set("CreationDate", `D:${getModificationDate()}`); + highlight.set("Rect", rect); + highlight.set("F", 4); + highlight.set("Border", [0, 0, 0]); + highlight.set("Rotate", rotation); + highlight.set("QuadPoints", quadPoints); + highlight.set("C", Array.from(color, c => c / 255)); + highlight.set("CA", opacity); + if (user) { + highlight.set("T", isAscii(user) ? user : stringToUTF16String(user, true)); + } + if (apRef || ap) { + const n = new Dict(xref); + highlight.set("AP", n); + n.set("N", apRef || ap); + } + return highlight; + } + static async createNewAppearanceStream(annotation, xref, params) { + const { + color, + rect, + outlines, + opacity + } = annotation; + const appearanceBuffer = [`${getPdfColor(color, true)}`, "/R0 gs"]; + const buffer = []; + for (const outline of outlines) { + buffer.length = 0; + buffer.push(`${numberToString(outline[0])} ${numberToString(outline[1])} m`); + for (let i = 2, ii = outline.length; i < ii; i += 2) { + buffer.push(`${numberToString(outline[i])} ${numberToString(outline[i + 1])} l`); + } + buffer.push("h"); + appearanceBuffer.push(buffer.join("\n")); + } + appearanceBuffer.push("f*"); + const appearance = appearanceBuffer.join("\n"); + const appearanceStreamDict = new Dict(xref); + appearanceStreamDict.set("FormType", 1); + appearanceStreamDict.set("Subtype", Name.get("Form")); + appearanceStreamDict.set("Type", Name.get("XObject")); + appearanceStreamDict.set("BBox", rect); + appearanceStreamDict.set("Length", appearance.length); + const resources = new Dict(xref); + const extGState = new Dict(xref); + resources.set("ExtGState", extGState); + appearanceStreamDict.set("Resources", resources); + const r0 = new Dict(xref); + extGState.set("R0", r0); + r0.set("BM", Name.get("Multiply")); + if (opacity !== 1) { + r0.set("ca", opacity); + r0.set("Type", Name.get("ExtGState")); + } + const ap = new StringStream(appearance); + ap.dict = appearanceStreamDict; + return ap; + } } class UnderlineAnnotation extends MarkupAnnotation { constructor(params) { super(params); const { @@ -56399,11 +56508,11 @@ const verbosity = getVerbosityLevel(); const { docId, apiVersion } = docParams; - const workerVersion = '4.0.240'; + const workerVersion = '4.0.275'; if (apiVersion !== workerVersion) { throw new Error(`The API version "${apiVersion}" does not match ` + `the Worker version "${workerVersion}".`); } const workerHandlerName = docId + "_worker"; let handler = new MessageHandler(workerHandlerName, docId, port); @@ -56960,10 +57069,10 @@ WorkerMessageHandler.initializeFromPort(self); } ;// CONCATENATED MODULE: ./src/pdf.worker.js -const pdfjsVersion = '4.0.240'; -const pdfjsBuild = 'ffbfd680e'; +const pdfjsVersion = '4.0.275'; +const pdfjsBuild = '4bf7ff202'; var __webpack_exports__WorkerMessageHandler = __webpack_exports__.WorkerMessageHandler; export { __webpack_exports__WorkerMessageHandler as WorkerMessageHandler }; diff --git a/toolkit/components/pdfjs/content/web/images/loading-dark.svg b/toolkit/components/pdfjs/content/web/images/loading-dark.svg deleted file mode 100644 --- a/toolkit/components/pdfjs/content/web/images/loading-dark.svg +++ /dev/null @@ -1,24 +0,0 @@ - \ No newline at end of file diff --git a/toolkit/components/pdfjs/content/web/viewer-geckoview.mjs b/toolkit/components/pdfjs/content/web/viewer-geckoview.mjs --- a/toolkit/components/pdfjs/content/web/viewer-geckoview.mjs +++ b/toolkit/components/pdfjs/content/web/viewer-geckoview.mjs @@ -542,10 +542,11 @@ AnnotationMode, build, CMapCompressionType, createValidAbsoluteUrl, DOMSVGFactory, + DrawLayer, FeatureTest, fetchData, getDocument, getFilenameFromUrl, getPdfFilenameFromUrl, @@ -557,10 +558,11 @@ isPdfFile, MissingPDFException, noContextMenu, normalizeUnicode, OPS, + Outliner, PasswordResponses, PDFDataRangeTransport, PDFDateString, PDFWorker, PermissionFlag, @@ -789,10 +791,11 @@ value: "resource://pdf.js/build/pdf.worker.mjs", kind: OptionKind.WORKER } }; ; +; const userOptions = Object.create(null); class AppOptions { constructor() { throw new Error("Cannot initialize AppOptions."); } @@ -4968,11 +4971,11 @@ #scrollModePageState = null; #onVisibilityChange = null; #scaleTimeoutId = null; #textLayerMode = TextLayerMode.ENABLE; constructor(options) { - const viewerVersion = '4.0.240'; + const viewerVersion = '4.0.275'; if (version !== viewerVersion) { throw new Error(`The API version "${version}" does not match the Viewer version "${viewerVersion}".`); } this.container = options.container; this.viewer = options.viewer || options.container.firstElementChild; @@ -9202,12 +9205,12 @@ -const pdfjsVersion = '4.0.240'; -const pdfjsBuild = 'ffbfd680e'; +const pdfjsVersion = '4.0.275'; +const pdfjsBuild = '4bf7ff202'; const AppConstants = null; window.PDFViewerApplication = PDFViewerApplication; window.PDFViewerApplicationConstants = AppConstants; window.PDFViewerApplicationOptions = AppOptions; function getViewerConfiguration() { diff --git a/toolkit/components/pdfjs/content/web/viewer.html b/toolkit/components/pdfjs/content/web/viewer.html --- a/toolkit/components/pdfjs/content/web/viewer.html +++ b/toolkit/components/pdfjs/content/web/viewer.html @@ -81,11 +81,13 @@