Merge pull request #11446 from Snuffleupagus/prettier
Enable auto-formatting of the entire code-base using Prettier (issue 11444)
This commit is contained in:
commit
81af207428
51
.eslintrc
51
.eslintrc
@ -11,6 +11,10 @@
|
||||
"unicorn",
|
||||
],
|
||||
|
||||
"extends": [
|
||||
"plugin:prettier/recommended"
|
||||
],
|
||||
|
||||
"env": {
|
||||
"browser": true,
|
||||
"es6": true,
|
||||
@ -47,7 +51,6 @@
|
||||
"no-empty": ["error", { "allowEmptyCatch": true, }],
|
||||
"no-ex-assign": "error",
|
||||
"no-extra-boolean-cast": "error",
|
||||
"no-extra-semi": "error",
|
||||
"no-func-assign": "error",
|
||||
"no-inner-declarations": ["error", "functions"],
|
||||
"no-invalid-regexp": "error",
|
||||
@ -84,9 +87,6 @@
|
||||
"no-implied-eval": "error",
|
||||
"no-iterator": "error",
|
||||
"no-lone-blocks": "error",
|
||||
"no-multi-spaces": ["error", {
|
||||
"ignoreEOLComments": true,
|
||||
}],
|
||||
"no-multi-str": "error",
|
||||
"no-new-func": "error",
|
||||
"no-new-wrappers": "error",
|
||||
@ -127,48 +127,16 @@
|
||||
}],
|
||||
|
||||
// Stylistic Issues
|
||||
"array-bracket-spacing": ["error", "never"],
|
||||
"block-spacing": ["error", "always"],
|
||||
"brace-style": ["error", "1tbs", {
|
||||
"allowSingleLine": false,
|
||||
}],
|
||||
"comma-dangle": ["error", {
|
||||
"arrays": "ignore",
|
||||
"objects": "always",
|
||||
"imports": "never",
|
||||
"exports": "always",
|
||||
"functions": "never",
|
||||
}],
|
||||
"comma-spacing": ["error", { "before": false, "after": true, }],
|
||||
"comma-style": ["error", "last"],
|
||||
"eol-last": "error",
|
||||
"func-call-spacing": ["error", "never"],
|
||||
"key-spacing": ["error", { "beforeColon": false, "afterColon": true, "mode": "strict", }],
|
||||
"keyword-spacing": ["error", { "before": true, "after": true, }],
|
||||
"linebreak-style": ["error", "unix"],
|
||||
"lines-between-class-members": ["error", "always"],
|
||||
"max-len": ["error", {
|
||||
"code": 80,
|
||||
"code": 1000,
|
||||
"comments": 80,
|
||||
"ignoreUrls": true
|
||||
}],
|
||||
"new-cap": ["error", { "newIsCap": true, "capIsNew": false, }],
|
||||
"new-parens": "error",
|
||||
"no-array-constructor": "error",
|
||||
"no-multiple-empty-lines": ["error", { "max": 1, "maxEOF": 0, "maxBOF": 1, }],
|
||||
"no-new-object": "error",
|
||||
"no-tabs": "error",
|
||||
"no-trailing-spaces": ["error", { "skipBlankLines": false, }],
|
||||
"no-whitespace-before-property": "error",
|
||||
"object-curly-spacing": ["error", "always"],
|
||||
"operator-linebreak": ["error", "after", { "overrides": { ":": "ignore", } }],
|
||||
"quotes": ["error", "single"],
|
||||
"semi-spacing": ["error", { "before": false, "after": true, }],
|
||||
"semi": ["error", "always"],
|
||||
"space-before-blocks": ["error", "always"],
|
||||
"space-before-function-paren": ["error", { "anonymous": "ignore", "named": "never", }],
|
||||
"space-in-parens": ["error", "never"],
|
||||
"space-infix-ops": ["error", { "int32Hint": false }],
|
||||
"space-unary-ops": ["error", { "words": true, "nonwords": false, }],
|
||||
"spaced-comment": ["error", "always", {
|
||||
"block": {
|
||||
"balanced": true,
|
||||
@ -176,12 +144,6 @@
|
||||
}],
|
||||
|
||||
// ECMAScript 6
|
||||
"arrow-body-style": ["error", "always"],
|
||||
"arrow-parens": ["error", "always"],
|
||||
"arrow-spacing": ["error", {
|
||||
"before": true,
|
||||
"after": true,
|
||||
}],
|
||||
"constructor-super": "error",
|
||||
"no-class-assign": "error",
|
||||
"no-confusing-arrow": "error",
|
||||
@ -197,7 +159,6 @@
|
||||
"avoidQuotes": true,
|
||||
}],
|
||||
"prefer-const": "off",
|
||||
"rest-spread-spacing": ["error", "never"],
|
||||
"sort-imports": ["error", {
|
||||
"ignoreCase": true,
|
||||
}],
|
||||
|
8
.prettierrc
Normal file
8
.prettierrc
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"endOfLine": "lf",
|
||||
"printWidth": 80,
|
||||
"semi": true,
|
||||
"tabWidth": 2,
|
||||
"trailingComma": "es5",
|
||||
"useTabs": false
|
||||
}
|
@ -13,15 +13,15 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
"use strict";
|
||||
|
||||
pdfjsLib.GlobalWorkerOptions.workerSrc =
|
||||
'../../node_modules/pdfjs-dist/build/pdf.worker.js';
|
||||
"../../node_modules/pdfjs-dist/build/pdf.worker.js";
|
||||
|
||||
var DEFAULT_URL = '../../test/pdfs/f1040.pdf';
|
||||
var DEFAULT_URL = "../../test/pdfs/f1040.pdf";
|
||||
var DEFAULT_SCALE = 1.0;
|
||||
|
||||
var container = document.getElementById('pageContainer');
|
||||
var container = document.getElementById("pageContainer");
|
||||
|
||||
// Fetch the PDF document from the URL using promises.
|
||||
var loadingTask = pdfjsLib.getDocument(DEFAULT_URL);
|
||||
@ -30,23 +30,24 @@ loadingTask.promise.then(function(doc) {
|
||||
var promise = Promise.resolve();
|
||||
|
||||
for (var i = 1; i <= doc.numPages; i++) {
|
||||
promise = promise.then(function (pageNum) {
|
||||
return doc.getPage(pageNum).then(function (pdfPage) {
|
||||
// Create the page view.
|
||||
var pdfPageView = new pdfjsViewer.PDFPageView({
|
||||
container: container,
|
||||
id: pageNum,
|
||||
scale: DEFAULT_SCALE,
|
||||
defaultViewport: pdfPage.getViewport({ scale: DEFAULT_SCALE, }),
|
||||
annotationLayerFactory:
|
||||
new pdfjsViewer.DefaultAnnotationLayerFactory(),
|
||||
renderInteractiveForms: true,
|
||||
});
|
||||
promise = promise.then(
|
||||
function(pageNum) {
|
||||
return doc.getPage(pageNum).then(function(pdfPage) {
|
||||
// Create the page view.
|
||||
var pdfPageView = new pdfjsViewer.PDFPageView({
|
||||
container: container,
|
||||
id: pageNum,
|
||||
scale: DEFAULT_SCALE,
|
||||
defaultViewport: pdfPage.getViewport({ scale: DEFAULT_SCALE }),
|
||||
annotationLayerFactory: new pdfjsViewer.DefaultAnnotationLayerFactory(),
|
||||
renderInteractiveForms: true,
|
||||
});
|
||||
|
||||
// Associate the actual page with the view and draw it.
|
||||
pdfPageView.setPdfPage(pdfPage);
|
||||
return pdfPageView.draw();
|
||||
});
|
||||
}.bind(null, i));
|
||||
// Associate the actual page with the view and draw it.
|
||||
pdfPageView.setPdfPage(pdfPage);
|
||||
return pdfPageView.draw();
|
||||
});
|
||||
}.bind(null, i)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
@ -1,36 +1,40 @@
|
||||
var gulp = require('gulp');
|
||||
var browserify = require('browserify');
|
||||
var streamify = require('gulp-streamify');
|
||||
var rename = require('gulp-rename');
|
||||
var uglify = require('gulp-uglify');
|
||||
var source = require('vinyl-source-stream');
|
||||
var gulp = require("gulp");
|
||||
var browserify = require("browserify");
|
||||
var streamify = require("gulp-streamify");
|
||||
var rename = require("gulp-rename");
|
||||
var uglify = require("gulp-uglify");
|
||||
var source = require("vinyl-source-stream");
|
||||
|
||||
var OUTPUT_PATH = '../../build/browserify';
|
||||
var TMP_FILE_PREFIX = '../../build/browserify_';
|
||||
var OUTPUT_PATH = "../../build/browserify";
|
||||
var TMP_FILE_PREFIX = "../../build/browserify_";
|
||||
|
||||
gulp.task('build-bundle', function() {
|
||||
return browserify('main.js', { output: TMP_FILE_PREFIX + 'main.tmp', })
|
||||
.ignore(require.resolve('pdfjs-dist/build/pdf.worker')) // Reducing size
|
||||
gulp.task("build-bundle", function() {
|
||||
return browserify("main.js", { output: TMP_FILE_PREFIX + "main.tmp" })
|
||||
.ignore(require.resolve("pdfjs-dist/build/pdf.worker")) // Reducing size
|
||||
.bundle()
|
||||
.pipe(source(TMP_FILE_PREFIX + 'main.tmp'))
|
||||
.pipe(source(TMP_FILE_PREFIX + "main.tmp"))
|
||||
.pipe(streamify(uglify()))
|
||||
.pipe(rename('main.bundle.js'))
|
||||
.pipe(rename("main.bundle.js"))
|
||||
.pipe(gulp.dest(OUTPUT_PATH));
|
||||
});
|
||||
|
||||
gulp.task('build-worker', function() {
|
||||
gulp.task("build-worker", function() {
|
||||
// We can create our own viewer (see worker.js) or use already defined one.
|
||||
var workerSrc = require.resolve('pdfjs-dist/build/pdf.worker.entry');
|
||||
return browserify(workerSrc, { output: TMP_FILE_PREFIX + 'worker.tmp', })
|
||||
var workerSrc = require.resolve("pdfjs-dist/build/pdf.worker.entry");
|
||||
return browserify(workerSrc, { output: TMP_FILE_PREFIX + "worker.tmp" })
|
||||
.bundle()
|
||||
.pipe(source(TMP_FILE_PREFIX + 'worker.tmp'))
|
||||
.pipe(streamify(uglify({
|
||||
compress: {
|
||||
sequences: false, // Chrome has issue with the generated code if true
|
||||
},
|
||||
})))
|
||||
.pipe(rename('pdf.worker.bundle.js'))
|
||||
.pipe(source(TMP_FILE_PREFIX + "worker.tmp"))
|
||||
.pipe(
|
||||
streamify(
|
||||
uglify({
|
||||
compress: {
|
||||
sequences: false, // Chrome has issue with the generated code if true
|
||||
},
|
||||
})
|
||||
)
|
||||
)
|
||||
.pipe(rename("pdf.worker.bundle.js"))
|
||||
.pipe(gulp.dest(OUTPUT_PATH));
|
||||
});
|
||||
|
||||
gulp.task('build', gulp.series('build-bundle', 'build-worker'));
|
||||
gulp.task("build", gulp.series("build-bundle", "build-worker"));
|
||||
|
@ -3,31 +3,33 @@
|
||||
|
||||
// Hello world example for browserify.
|
||||
|
||||
var pdfjsLib = require('pdfjs-dist');
|
||||
var pdfjsLib = require("pdfjs-dist");
|
||||
|
||||
var pdfPath = '../learning/helloworld.pdf';
|
||||
var pdfPath = "../learning/helloworld.pdf";
|
||||
|
||||
// Setting worker path to worker bundle.
|
||||
pdfjsLib.GlobalWorkerOptions.workerSrc =
|
||||
'../../build/browserify/pdf.worker.bundle.js';
|
||||
"../../build/browserify/pdf.worker.bundle.js";
|
||||
|
||||
// Loading a document.
|
||||
var loadingTask = pdfjsLib.getDocument(pdfPath);
|
||||
loadingTask.promise.then(function (pdfDocument) {
|
||||
// Request a first page
|
||||
return pdfDocument.getPage(1).then(function (pdfPage) {
|
||||
// Display page on the existing canvas with 100% scale.
|
||||
var viewport = pdfPage.getViewport({ scale: 1.0, });
|
||||
var canvas = document.getElementById('theCanvas');
|
||||
canvas.width = viewport.width;
|
||||
canvas.height = viewport.height;
|
||||
var ctx = canvas.getContext('2d');
|
||||
var renderTask = pdfPage.render({
|
||||
canvasContext: ctx,
|
||||
viewport: viewport,
|
||||
loadingTask.promise
|
||||
.then(function(pdfDocument) {
|
||||
// Request a first page
|
||||
return pdfDocument.getPage(1).then(function(pdfPage) {
|
||||
// Display page on the existing canvas with 100% scale.
|
||||
var viewport = pdfPage.getViewport({ scale: 1.0 });
|
||||
var canvas = document.getElementById("theCanvas");
|
||||
canvas.width = viewport.width;
|
||||
canvas.height = viewport.height;
|
||||
var ctx = canvas.getContext("2d");
|
||||
var renderTask = pdfPage.render({
|
||||
canvasContext: ctx,
|
||||
viewport: viewport,
|
||||
});
|
||||
return renderTask.promise;
|
||||
});
|
||||
return renderTask.promise;
|
||||
})
|
||||
.catch(function(reason) {
|
||||
console.error("Error: " + reason);
|
||||
});
|
||||
}).catch(function (reason) {
|
||||
console.error('Error: ' + reason);
|
||||
});
|
||||
|
@ -3,5 +3,7 @@
|
||||
|
||||
// Hello world example for browserify: worker bundle.
|
||||
|
||||
(typeof window !== 'undefined' ? window : {}).pdfjsWorker =
|
||||
require('pdfjs-dist/build/pdf.worker');
|
||||
(typeof window !== "undefined"
|
||||
? window
|
||||
: {}
|
||||
).pdfjsWorker = require("pdfjs-dist/build/pdf.worker");
|
||||
|
@ -13,28 +13,27 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
"use strict";
|
||||
|
||||
if (!pdfjsLib.getDocument || !pdfjsViewer.PDFPageView) {
|
||||
alert('Please build the pdfjs-dist library using\n' +
|
||||
' `gulp dist-install`');
|
||||
alert("Please build the pdfjs-dist library using\n `gulp dist-install`");
|
||||
}
|
||||
|
||||
// The workerSrc property shall be specified.
|
||||
//
|
||||
pdfjsLib.GlobalWorkerOptions.workerSrc =
|
||||
'../../node_modules/pdfjs-dist/build/pdf.worker.js';
|
||||
"../../node_modules/pdfjs-dist/build/pdf.worker.js";
|
||||
|
||||
// Some PDFs need external cmaps.
|
||||
//
|
||||
var CMAP_URL = '../../node_modules/pdfjs-dist/cmaps/';
|
||||
var CMAP_URL = "../../node_modules/pdfjs-dist/cmaps/";
|
||||
var CMAP_PACKED = true;
|
||||
|
||||
var DEFAULT_URL = '../../web/compressed.tracemonkey-pldi-09.pdf';
|
||||
var DEFAULT_URL = "../../web/compressed.tracemonkey-pldi-09.pdf";
|
||||
var PAGE_TO_VIEW = 1;
|
||||
var SCALE = 1.0;
|
||||
|
||||
var container = document.getElementById('pageContainer');
|
||||
var container = document.getElementById("pageContainer");
|
||||
|
||||
// Loading document.
|
||||
var loadingTask = pdfjsLib.getDocument({
|
||||
@ -44,13 +43,13 @@ var loadingTask = pdfjsLib.getDocument({
|
||||
});
|
||||
loadingTask.promise.then(function(pdfDocument) {
|
||||
// Document loaded, retrieving the page.
|
||||
return pdfDocument.getPage(PAGE_TO_VIEW).then(function (pdfPage) {
|
||||
return pdfDocument.getPage(PAGE_TO_VIEW).then(function(pdfPage) {
|
||||
// Creating the page view with default parameters.
|
||||
var pdfPageView = new pdfjsViewer.PDFPageView({
|
||||
container: container,
|
||||
id: PAGE_TO_VIEW,
|
||||
scale: SCALE,
|
||||
defaultViewport: pdfPage.getViewport({ scale: SCALE, }),
|
||||
defaultViewport: pdfPage.getViewport({ scale: SCALE }),
|
||||
// We can enable text/annotations layers, if needed
|
||||
textLayerFactory: new pdfjsViewer.DefaultTextLayerFactory(),
|
||||
annotationLayerFactory: new pdfjsViewer.DefaultAnnotationLayerFactory(),
|
||||
|
@ -13,27 +13,26 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
"use strict";
|
||||
|
||||
if (!pdfjsLib.getDocument || !pdfjsViewer.PDFViewer) {
|
||||
alert('Please build the pdfjs-dist library using\n' +
|
||||
' `gulp dist-install`');
|
||||
alert("Please build the pdfjs-dist library using\n `gulp dist-install`");
|
||||
}
|
||||
|
||||
// The workerSrc property shall be specified.
|
||||
//
|
||||
pdfjsLib.GlobalWorkerOptions.workerSrc =
|
||||
'../../node_modules/pdfjs-dist/build/pdf.worker.js';
|
||||
"../../node_modules/pdfjs-dist/build/pdf.worker.js";
|
||||
|
||||
// Some PDFs need external cmaps.
|
||||
//
|
||||
var CMAP_URL = '../../node_modules/pdfjs-dist/cmaps/';
|
||||
var CMAP_URL = "../../node_modules/pdfjs-dist/cmaps/";
|
||||
var CMAP_PACKED = true;
|
||||
|
||||
var DEFAULT_URL = '../../web/compressed.tracemonkey-pldi-09.pdf';
|
||||
var SEARCH_FOR = ''; // try 'Mozilla';
|
||||
var DEFAULT_URL = "../../web/compressed.tracemonkey-pldi-09.pdf";
|
||||
var SEARCH_FOR = ""; // try 'Mozilla';
|
||||
|
||||
var container = document.getElementById('viewerContainer');
|
||||
var container = document.getElementById("viewerContainer");
|
||||
|
||||
// (Optionally) enable hyperlinks within PDF files.
|
||||
var pdfLinkService = new pdfjsViewer.PDFLinkService();
|
||||
@ -50,12 +49,13 @@ var pdfViewer = new pdfjsViewer.PDFViewer({
|
||||
});
|
||||
pdfLinkService.setViewer(pdfViewer);
|
||||
|
||||
document.addEventListener('pagesinit', function () {
|
||||
document.addEventListener("pagesinit", function() {
|
||||
// We can use pdfViewer now, e.g. let's change default scale.
|
||||
pdfViewer.currentScaleValue = 'page-width';
|
||||
pdfViewer.currentScaleValue = "page-width";
|
||||
|
||||
if (SEARCH_FOR) { // We can try search for things
|
||||
pdfFindController.executeCommand('find', { query: SEARCH_FOR, });
|
||||
// We can try searching for things.
|
||||
if (SEARCH_FOR) {
|
||||
pdfFindController.executeCommand("find", { query: SEARCH_FOR });
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -13,27 +13,26 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
"use strict";
|
||||
|
||||
if (!pdfjsLib.getDocument || !pdfjsViewer.PDFSinglePageViewer) {
|
||||
alert('Please build the pdfjs-dist library using\n' +
|
||||
' `gulp dist-install`');
|
||||
alert("Please build the pdfjs-dist library using\n `gulp dist-install`");
|
||||
}
|
||||
|
||||
// The workerSrc property shall be specified.
|
||||
//
|
||||
pdfjsLib.GlobalWorkerOptions.workerSrc =
|
||||
'../../node_modules/pdfjs-dist/build/pdf.worker.js';
|
||||
"../../node_modules/pdfjs-dist/build/pdf.worker.js";
|
||||
|
||||
// Some PDFs need external cmaps.
|
||||
//
|
||||
var CMAP_URL = '../../node_modules/pdfjs-dist/cmaps/';
|
||||
var CMAP_URL = "../../node_modules/pdfjs-dist/cmaps/";
|
||||
var CMAP_PACKED = true;
|
||||
|
||||
var DEFAULT_URL = '../../web/compressed.tracemonkey-pldi-09.pdf';
|
||||
var SEARCH_FOR = ''; // try 'Mozilla';
|
||||
var DEFAULT_URL = "../../web/compressed.tracemonkey-pldi-09.pdf";
|
||||
var SEARCH_FOR = ""; // try 'Mozilla';
|
||||
|
||||
var container = document.getElementById('viewerContainer');
|
||||
var container = document.getElementById("viewerContainer");
|
||||
|
||||
// (Optionally) enable hyperlinks within PDF files.
|
||||
var pdfLinkService = new pdfjsViewer.PDFLinkService();
|
||||
@ -50,12 +49,13 @@ var pdfSinglePageViewer = new pdfjsViewer.PDFSinglePageViewer({
|
||||
});
|
||||
pdfLinkService.setViewer(pdfSinglePageViewer);
|
||||
|
||||
document.addEventListener('pagesinit', function () {
|
||||
document.addEventListener("pagesinit", function() {
|
||||
// We can use pdfSinglePageViewer now, e.g. let's change default scale.
|
||||
pdfSinglePageViewer.currentScaleValue = 'page-width';
|
||||
pdfSinglePageViewer.currentScaleValue = "page-width";
|
||||
|
||||
if (SEARCH_FOR) { // We can try search for things
|
||||
pdfFindController.executeCommand('find', { query: SEARCH_FOR, });
|
||||
// We can try searching for things.
|
||||
if (SEARCH_FOR) {
|
||||
pdfFindController.executeCommand("find", { query: SEARCH_FOR });
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -13,39 +13,40 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
"use strict";
|
||||
|
||||
if (!pdfjsImageDecoders.JpegImage) {
|
||||
alert('Please build the pdfjs-dist library using `gulp dist-install`');
|
||||
alert("Please build the pdfjs-dist library using `gulp dist-install`");
|
||||
}
|
||||
|
||||
var JPEG_IMAGE = 'fish.jpg';
|
||||
var JPEG_IMAGE = "fish.jpg";
|
||||
|
||||
var jpegCanvas = document.getElementById('jpegCanvas');
|
||||
var jpegCtx = jpegCanvas.getContext('2d');
|
||||
var jpegCanvas = document.getElementById("jpegCanvas");
|
||||
var jpegCtx = jpegCanvas.getContext("2d");
|
||||
|
||||
// Load the image data, and convert it to a Uint8Array.
|
||||
//
|
||||
var nonBinaryRequest = false;
|
||||
var request = new XMLHttpRequest();
|
||||
request.open('GET', JPEG_IMAGE, false);
|
||||
request.open("GET", JPEG_IMAGE, false);
|
||||
try {
|
||||
request.responseType = 'arraybuffer';
|
||||
nonBinaryRequest = request.responseType !== 'arraybuffer';
|
||||
request.responseType = "arraybuffer";
|
||||
nonBinaryRequest = request.responseType !== "arraybuffer";
|
||||
} catch (e) {
|
||||
nonBinaryRequest = true;
|
||||
}
|
||||
if (nonBinaryRequest && request.overrideMimeType) {
|
||||
request.overrideMimeType('text/plain; charset=x-user-defined');
|
||||
request.overrideMimeType("text/plain; charset=x-user-defined");
|
||||
}
|
||||
request.send(null);
|
||||
|
||||
var typedArrayImage;
|
||||
if (nonBinaryRequest) {
|
||||
var str = request.responseText, length = str.length;
|
||||
var str = request.responseText,
|
||||
length = str.length;
|
||||
var bytes = new Uint8Array(length);
|
||||
for (var i = 0; i < length; ++i) {
|
||||
bytes[i] = str.charCodeAt(i) & 0xFF;
|
||||
bytes[i] = str.charCodeAt(i) & 0xff;
|
||||
}
|
||||
typedArrayImage = bytes;
|
||||
} else {
|
||||
@ -57,7 +58,8 @@ if (nonBinaryRequest) {
|
||||
var jpegImage = new pdfjsImageDecoders.JpegImage();
|
||||
jpegImage.parse(typedArrayImage);
|
||||
|
||||
var width = jpegImage.width, height = jpegImage.height;
|
||||
var width = jpegImage.width,
|
||||
height = jpegImage.height;
|
||||
var jpegData = jpegImage.getData({
|
||||
width: width,
|
||||
height: height,
|
||||
@ -68,7 +70,7 @@ var jpegData = jpegImage.getData({
|
||||
//
|
||||
var imageData = jpegCtx.createImageData(width, height);
|
||||
var imageBytes = imageData.data;
|
||||
for (var j = 0, k = 0, jj = width * height * 4; j < jj;) {
|
||||
for (var j = 0, k = 0, jj = width * height * 4; j < jj; ) {
|
||||
imageBytes[j++] = jpegData[k++];
|
||||
imageBytes[j++] = jpegData[k++];
|
||||
imageBytes[j++] = jpegData[k++];
|
||||
|
@ -13,26 +13,26 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
"use strict";
|
||||
|
||||
if (!pdfjsLib.getDocument || !pdfjsViewer.PDFViewer) {
|
||||
alert('Please build the pdfjs-dist library using\n `gulp dist-install`');
|
||||
alert("Please build the pdfjs-dist library using\n `gulp dist-install`");
|
||||
}
|
||||
|
||||
var USE_ONLY_CSS_ZOOM = true;
|
||||
var TEXT_LAYER_MODE = 0; // DISABLE
|
||||
var MAX_IMAGE_SIZE = 1024 * 1024;
|
||||
var CMAP_URL = '../../node_modules/pdfjs-dist/cmaps/';
|
||||
var CMAP_URL = "../../node_modules/pdfjs-dist/cmaps/";
|
||||
var CMAP_PACKED = true;
|
||||
|
||||
pdfjsLib.GlobalWorkerOptions.workerSrc =
|
||||
'../../node_modules/pdfjs-dist/build/pdf.worker.js';
|
||||
"../../node_modules/pdfjs-dist/build/pdf.worker.js";
|
||||
|
||||
var DEFAULT_URL = '../../web/compressed.tracemonkey-pldi-09.pdf';
|
||||
var DEFAULT_URL = "../../web/compressed.tracemonkey-pldi-09.pdf";
|
||||
var DEFAULT_SCALE_DELTA = 1.1;
|
||||
var MIN_SCALE = 0.25;
|
||||
var MAX_SCALE = 10.0;
|
||||
var DEFAULT_SCALE_VALUE = 'auto';
|
||||
var DEFAULT_SCALE_VALUE = "auto";
|
||||
|
||||
var PDFViewerApplication = {
|
||||
pdfLoadingTask: null,
|
||||
@ -49,10 +49,12 @@ var PDFViewerApplication = {
|
||||
open: function(params) {
|
||||
if (this.pdfLoadingTask) {
|
||||
// We need to destroy already opened document
|
||||
return this.close().then(function () {
|
||||
// ... and repeat the open() call.
|
||||
return this.open(params);
|
||||
}.bind(this));
|
||||
return this.close().then(
|
||||
function() {
|
||||
// ... and repeat the open() call.
|
||||
return this.open(params);
|
||||
}.bind(this)
|
||||
);
|
||||
}
|
||||
|
||||
var url = params.url;
|
||||
@ -68,45 +70,60 @@ var PDFViewerApplication = {
|
||||
});
|
||||
this.pdfLoadingTask = loadingTask;
|
||||
|
||||
loadingTask.onProgress = function (progressData) {
|
||||
loadingTask.onProgress = function(progressData) {
|
||||
self.progress(progressData.loaded / progressData.total);
|
||||
};
|
||||
|
||||
return loadingTask.promise.then(function (pdfDocument) {
|
||||
// Document loaded, specifying document for the viewer.
|
||||
self.pdfDocument = pdfDocument;
|
||||
self.pdfViewer.setDocument(pdfDocument);
|
||||
self.pdfLinkService.setDocument(pdfDocument);
|
||||
self.pdfHistory.initialize({ fingerprint: pdfDocument.fingerprint, });
|
||||
return loadingTask.promise.then(
|
||||
function(pdfDocument) {
|
||||
// Document loaded, specifying document for the viewer.
|
||||
self.pdfDocument = pdfDocument;
|
||||
self.pdfViewer.setDocument(pdfDocument);
|
||||
self.pdfLinkService.setDocument(pdfDocument);
|
||||
self.pdfHistory.initialize({ fingerprint: pdfDocument.fingerprint });
|
||||
|
||||
self.loadingBar.hide();
|
||||
self.setTitleUsingMetadata(pdfDocument);
|
||||
}, function (exception) {
|
||||
var message = exception && exception.message;
|
||||
var l10n = self.l10n;
|
||||
var loadingErrorMessage;
|
||||
self.loadingBar.hide();
|
||||
self.setTitleUsingMetadata(pdfDocument);
|
||||
},
|
||||
function(exception) {
|
||||
var message = exception && exception.message;
|
||||
var l10n = self.l10n;
|
||||
var loadingErrorMessage;
|
||||
|
||||
if (exception instanceof pdfjsLib.InvalidPDFException) {
|
||||
// change error message also for other builds
|
||||
loadingErrorMessage = l10n.get('invalid_file_error', null,
|
||||
'Invalid or corrupted PDF file.');
|
||||
} else if (exception instanceof pdfjsLib.MissingPDFException) {
|
||||
// special message for missing PDFs
|
||||
loadingErrorMessage = l10n.get('missing_file_error', null,
|
||||
'Missing PDF file.');
|
||||
} else if (exception instanceof pdfjsLib.UnexpectedResponseException) {
|
||||
loadingErrorMessage = l10n.get('unexpected_response_error', null,
|
||||
'Unexpected server response.');
|
||||
} else {
|
||||
loadingErrorMessage = l10n.get('loading_error', null,
|
||||
'An error occurred while loading the PDF.');
|
||||
if (exception instanceof pdfjsLib.InvalidPDFException) {
|
||||
// change error message also for other builds
|
||||
loadingErrorMessage = l10n.get(
|
||||
"invalid_file_error",
|
||||
null,
|
||||
"Invalid or corrupted PDF file."
|
||||
);
|
||||
} else if (exception instanceof pdfjsLib.MissingPDFException) {
|
||||
// special message for missing PDFs
|
||||
loadingErrorMessage = l10n.get(
|
||||
"missing_file_error",
|
||||
null,
|
||||
"Missing PDF file."
|
||||
);
|
||||
} else if (exception instanceof pdfjsLib.UnexpectedResponseException) {
|
||||
loadingErrorMessage = l10n.get(
|
||||
"unexpected_response_error",
|
||||
null,
|
||||
"Unexpected server response."
|
||||
);
|
||||
} else {
|
||||
loadingErrorMessage = l10n.get(
|
||||
"loading_error",
|
||||
null,
|
||||
"An error occurred while loading the PDF."
|
||||
);
|
||||
}
|
||||
|
||||
loadingErrorMessage.then(function(msg) {
|
||||
self.error(msg, { message: message });
|
||||
});
|
||||
self.loadingBar.hide();
|
||||
}
|
||||
|
||||
loadingErrorMessage.then(function (msg) {
|
||||
self.error(msg, { message: message, });
|
||||
});
|
||||
self.loadingBar.hide();
|
||||
});
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -115,8 +132,8 @@ var PDFViewerApplication = {
|
||||
* destruction is completed.
|
||||
*/
|
||||
close: function() {
|
||||
var errorWrapper = document.getElementById('errorWrapper');
|
||||
errorWrapper.setAttribute('hidden', 'true');
|
||||
var errorWrapper = document.getElementById("errorWrapper");
|
||||
errorWrapper.setAttribute("hidden", "true");
|
||||
|
||||
if (!this.pdfLoadingTask) {
|
||||
return Promise.resolve();
|
||||
@ -140,9 +157,9 @@ var PDFViewerApplication = {
|
||||
},
|
||||
|
||||
get loadingBar() {
|
||||
var bar = new pdfjsViewer.ProgressBar('#loadingBar', {});
|
||||
var bar = new pdfjsViewer.ProgressBar("#loadingBar", {});
|
||||
|
||||
return pdfjsLib.shadow(this, 'loadingBar', bar);
|
||||
return pdfjsLib.shadow(this, "loadingBar", bar);
|
||||
},
|
||||
|
||||
setTitleUsingUrl: function pdfViewSetTitleUsingUrl(url) {
|
||||
@ -160,99 +177,125 @@ var PDFViewerApplication = {
|
||||
setTitleUsingMetadata: function(pdfDocument) {
|
||||
var self = this;
|
||||
pdfDocument.getMetadata().then(function(data) {
|
||||
var info = data.info, metadata = data.metadata;
|
||||
var info = data.info,
|
||||
metadata = data.metadata;
|
||||
self.documentInfo = info;
|
||||
self.metadata = metadata;
|
||||
|
||||
// Provides some basic debug information
|
||||
console.log('PDF ' + pdfDocument.fingerprint + ' [' +
|
||||
info.PDFFormatVersion + ' ' + (info.Producer || '-').trim() +
|
||||
' / ' + (info.Creator || '-').trim() + ']' +
|
||||
' (PDF.js: ' + (pdfjsLib.version || '-') + ')');
|
||||
console.log(
|
||||
"PDF " +
|
||||
pdfDocument.fingerprint +
|
||||
" [" +
|
||||
info.PDFFormatVersion +
|
||||
" " +
|
||||
(info.Producer || "-").trim() +
|
||||
" / " +
|
||||
(info.Creator || "-").trim() +
|
||||
"]" +
|
||||
" (PDF.js: " +
|
||||
(pdfjsLib.version || "-") +
|
||||
")"
|
||||
);
|
||||
|
||||
var pdfTitle;
|
||||
if (metadata && metadata.has('dc:title')) {
|
||||
var title = metadata.get('dc:title');
|
||||
if (metadata && metadata.has("dc:title")) {
|
||||
var title = metadata.get("dc:title");
|
||||
// Ghostscript sometimes returns 'Untitled', so prevent setting the
|
||||
// title to 'Untitled.
|
||||
if (title !== 'Untitled') {
|
||||
if (title !== "Untitled") {
|
||||
pdfTitle = title;
|
||||
}
|
||||
}
|
||||
|
||||
if (!pdfTitle && info && info['Title']) {
|
||||
pdfTitle = info['Title'];
|
||||
if (!pdfTitle && info && info["Title"]) {
|
||||
pdfTitle = info["Title"];
|
||||
}
|
||||
|
||||
if (pdfTitle) {
|
||||
self.setTitle(pdfTitle + ' - ' + document.title);
|
||||
self.setTitle(pdfTitle + " - " + document.title);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
setTitle: function pdfViewSetTitle(title) {
|
||||
document.title = title;
|
||||
document.getElementById('title').textContent = title;
|
||||
document.getElementById("title").textContent = title;
|
||||
},
|
||||
|
||||
error: function pdfViewError(message, moreInfo) {
|
||||
var l10n = this.l10n;
|
||||
var moreInfoText = [l10n.get('error_version_info',
|
||||
{ version: pdfjsLib.version || '?',
|
||||
build: pdfjsLib.build || '?', },
|
||||
'PDF.js v{{version}} (build: {{build}})')];
|
||||
var moreInfoText = [
|
||||
l10n.get(
|
||||
"error_version_info",
|
||||
{ version: pdfjsLib.version || "?", build: pdfjsLib.build || "?" },
|
||||
"PDF.js v{{version}} (build: {{build}})"
|
||||
),
|
||||
];
|
||||
|
||||
if (moreInfo) {
|
||||
moreInfoText.push(
|
||||
l10n.get('error_message', { message: moreInfo.message, },
|
||||
'Message: {{message}}'));
|
||||
l10n.get(
|
||||
"error_message",
|
||||
{ message: moreInfo.message },
|
||||
"Message: {{message}}"
|
||||
)
|
||||
);
|
||||
if (moreInfo.stack) {
|
||||
moreInfoText.push(
|
||||
l10n.get('error_stack', { stack: moreInfo.stack, },
|
||||
'Stack: {{stack}}'));
|
||||
l10n.get("error_stack", { stack: moreInfo.stack }, "Stack: {{stack}}")
|
||||
);
|
||||
} else {
|
||||
if (moreInfo.filename) {
|
||||
moreInfoText.push(
|
||||
l10n.get('error_file', { file: moreInfo.filename, },
|
||||
'File: {{file}}'));
|
||||
l10n.get(
|
||||
"error_file",
|
||||
{ file: moreInfo.filename },
|
||||
"File: {{file}}"
|
||||
)
|
||||
);
|
||||
}
|
||||
if (moreInfo.lineNumber) {
|
||||
moreInfoText.push(
|
||||
l10n.get('error_line', { line: moreInfo.lineNumber, },
|
||||
'Line: {{line}}'));
|
||||
l10n.get(
|
||||
"error_line",
|
||||
{ line: moreInfo.lineNumber },
|
||||
"Line: {{line}}"
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var errorWrapper = document.getElementById('errorWrapper');
|
||||
errorWrapper.removeAttribute('hidden');
|
||||
var errorWrapper = document.getElementById("errorWrapper");
|
||||
errorWrapper.removeAttribute("hidden");
|
||||
|
||||
var errorMessage = document.getElementById('errorMessage');
|
||||
var errorMessage = document.getElementById("errorMessage");
|
||||
errorMessage.textContent = message;
|
||||
|
||||
var closeButton = document.getElementById('errorClose');
|
||||
var closeButton = document.getElementById("errorClose");
|
||||
closeButton.onclick = function() {
|
||||
errorWrapper.setAttribute('hidden', 'true');
|
||||
errorWrapper.setAttribute("hidden", "true");
|
||||
};
|
||||
|
||||
var errorMoreInfo = document.getElementById('errorMoreInfo');
|
||||
var moreInfoButton = document.getElementById('errorShowMore');
|
||||
var lessInfoButton = document.getElementById('errorShowLess');
|
||||
var errorMoreInfo = document.getElementById("errorMoreInfo");
|
||||
var moreInfoButton = document.getElementById("errorShowMore");
|
||||
var lessInfoButton = document.getElementById("errorShowLess");
|
||||
moreInfoButton.onclick = function() {
|
||||
errorMoreInfo.removeAttribute('hidden');
|
||||
moreInfoButton.setAttribute('hidden', 'true');
|
||||
lessInfoButton.removeAttribute('hidden');
|
||||
errorMoreInfo.style.height = errorMoreInfo.scrollHeight + 'px';
|
||||
errorMoreInfo.removeAttribute("hidden");
|
||||
moreInfoButton.setAttribute("hidden", "true");
|
||||
lessInfoButton.removeAttribute("hidden");
|
||||
errorMoreInfo.style.height = errorMoreInfo.scrollHeight + "px";
|
||||
};
|
||||
lessInfoButton.onclick = function() {
|
||||
errorMoreInfo.setAttribute('hidden', 'true');
|
||||
moreInfoButton.removeAttribute('hidden');
|
||||
lessInfoButton.setAttribute('hidden', 'true');
|
||||
errorMoreInfo.setAttribute("hidden", "true");
|
||||
moreInfoButton.removeAttribute("hidden");
|
||||
lessInfoButton.setAttribute("hidden", "true");
|
||||
};
|
||||
moreInfoButton.removeAttribute('hidden');
|
||||
lessInfoButton.setAttribute('hidden', 'true');
|
||||
Promise.all(moreInfoText).then(function (parts) {
|
||||
errorMoreInfo.value = parts.join('\n');
|
||||
moreInfoButton.removeAttribute("hidden");
|
||||
lessInfoButton.setAttribute("hidden", "true");
|
||||
Promise.all(moreInfoText).then(function(parts) {
|
||||
errorMoreInfo.value = parts.join("\n");
|
||||
});
|
||||
},
|
||||
|
||||
@ -302,7 +345,7 @@ var PDFViewerApplication = {
|
||||
|
||||
this.l10n = pdfjsViewer.NullL10n;
|
||||
|
||||
var container = document.getElementById('viewerContainer');
|
||||
var container = document.getElementById("viewerContainer");
|
||||
var pdfViewer = new pdfjsViewer.PDFViewer({
|
||||
container: container,
|
||||
linkService: linkService,
|
||||
@ -318,69 +361,77 @@ var PDFViewerApplication = {
|
||||
});
|
||||
linkService.setHistory(this.pdfHistory);
|
||||
|
||||
document.getElementById('previous').addEventListener('click', function() {
|
||||
document.getElementById("previous").addEventListener("click", function() {
|
||||
PDFViewerApplication.page--;
|
||||
});
|
||||
|
||||
document.getElementById('next').addEventListener('click', function() {
|
||||
document.getElementById("next").addEventListener("click", function() {
|
||||
PDFViewerApplication.page++;
|
||||
});
|
||||
|
||||
document.getElementById('zoomIn').addEventListener('click', function() {
|
||||
document.getElementById("zoomIn").addEventListener("click", function() {
|
||||
PDFViewerApplication.zoomIn();
|
||||
});
|
||||
|
||||
document.getElementById('zoomOut').addEventListener('click', function() {
|
||||
document.getElementById("zoomOut").addEventListener("click", function() {
|
||||
PDFViewerApplication.zoomOut();
|
||||
});
|
||||
|
||||
document.getElementById('pageNumber').addEventListener('click', function() {
|
||||
document.getElementById("pageNumber").addEventListener("click", function() {
|
||||
this.select();
|
||||
});
|
||||
|
||||
document.getElementById('pageNumber').addEventListener('change',
|
||||
function() {
|
||||
PDFViewerApplication.page = (this.value | 0);
|
||||
document
|
||||
.getElementById("pageNumber")
|
||||
.addEventListener("change", function() {
|
||||
PDFViewerApplication.page = this.value | 0;
|
||||
|
||||
// Ensure that the page number input displays the correct value,
|
||||
// even if the value entered by the user was invalid
|
||||
// (e.g. a floating point number).
|
||||
if (this.value !== PDFViewerApplication.page.toString()) {
|
||||
this.value = PDFViewerApplication.page;
|
||||
}
|
||||
});
|
||||
// Ensure that the page number input displays the correct value,
|
||||
// even if the value entered by the user was invalid
|
||||
// (e.g. a floating point number).
|
||||
if (this.value !== PDFViewerApplication.page.toString()) {
|
||||
this.value = PDFViewerApplication.page;
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener('pagesinit', function () {
|
||||
document.addEventListener("pagesinit", function() {
|
||||
// We can use pdfViewer now, e.g. let's change default scale.
|
||||
pdfViewer.currentScaleValue = DEFAULT_SCALE_VALUE;
|
||||
});
|
||||
|
||||
document.addEventListener('pagechanging', function (evt) {
|
||||
var page = evt.detail.pageNumber;
|
||||
var numPages = PDFViewerApplication.pagesCount;
|
||||
document.addEventListener(
|
||||
"pagechanging",
|
||||
function(evt) {
|
||||
var page = evt.detail.pageNumber;
|
||||
var numPages = PDFViewerApplication.pagesCount;
|
||||
|
||||
document.getElementById('pageNumber').value = page;
|
||||
document.getElementById('previous').disabled = (page <= 1);
|
||||
document.getElementById('next').disabled = (page >= numPages);
|
||||
}, true);
|
||||
document.getElementById("pageNumber").value = page;
|
||||
document.getElementById("previous").disabled = page <= 1;
|
||||
document.getElementById("next").disabled = page >= numPages;
|
||||
},
|
||||
true
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
PDFViewerApplication.initUI();
|
||||
}, true);
|
||||
document.addEventListener(
|
||||
"DOMContentLoaded",
|
||||
function() {
|
||||
PDFViewerApplication.initUI();
|
||||
},
|
||||
true
|
||||
);
|
||||
|
||||
(function animationStartedClosure() {
|
||||
// The offsetParent is not set until the PDF.js iframe or object is visible.
|
||||
// Waiting for first animation.
|
||||
PDFViewerApplication.animationStartedPromise = new Promise(
|
||||
function (resolve) {
|
||||
window.requestAnimationFrame(resolve);
|
||||
});
|
||||
PDFViewerApplication.animationStartedPromise = new Promise(function(resolve) {
|
||||
window.requestAnimationFrame(resolve);
|
||||
});
|
||||
})();
|
||||
|
||||
// We need to delay opening until all HTML is loaded.
|
||||
PDFViewerApplication.animationStartedPromise.then(function () {
|
||||
PDFViewerApplication.animationStartedPromise.then(function() {
|
||||
PDFViewerApplication.open({
|
||||
url: DEFAULT_URL,
|
||||
});
|
||||
|
@ -2,10 +2,18 @@
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
function xmlEncode(s) {
|
||||
var i = 0, ch;
|
||||
var i = 0,
|
||||
ch;
|
||||
s = String(s);
|
||||
while (i < s.length && (ch = s[i]) !== '&' && ch !== '<' &&
|
||||
ch !== '\"' && ch !== '\n' && ch !== '\r' && ch !== '\t') {
|
||||
while (
|
||||
i < s.length &&
|
||||
(ch = s[i]) !== "&" &&
|
||||
ch !== "<" &&
|
||||
ch !== '"' &&
|
||||
ch !== "\n" &&
|
||||
ch !== "\r" &&
|
||||
ch !== "\t"
|
||||
) {
|
||||
i++;
|
||||
}
|
||||
if (i >= s.length) {
|
||||
@ -15,23 +23,23 @@ function xmlEncode(s) {
|
||||
while (i < s.length) {
|
||||
ch = s[i++];
|
||||
switch (ch) {
|
||||
case '&':
|
||||
buf += '&';
|
||||
case "&":
|
||||
buf += "&";
|
||||
break;
|
||||
case '<':
|
||||
buf += '<';
|
||||
case "<":
|
||||
buf += "<";
|
||||
break;
|
||||
case '\"':
|
||||
buf += '"';
|
||||
case '"':
|
||||
buf += """;
|
||||
break;
|
||||
case '\n':
|
||||
buf += '
';
|
||||
case "\n":
|
||||
buf += "
";
|
||||
break;
|
||||
case '\r':
|
||||
buf += '
';
|
||||
case "\r":
|
||||
buf += "
";
|
||||
break;
|
||||
case '\t':
|
||||
buf += '	';
|
||||
case "\t":
|
||||
buf += "	";
|
||||
break;
|
||||
default:
|
||||
buf += ch;
|
||||
@ -45,9 +53,9 @@ function DOMElement(name) {
|
||||
this.nodeName = name;
|
||||
this.childNodes = [];
|
||||
this.attributes = {};
|
||||
this.textContent = '';
|
||||
this.textContent = "";
|
||||
|
||||
if (name === 'style') {
|
||||
if (name === "style") {
|
||||
this.sheet = {
|
||||
cssRules: [],
|
||||
insertRule: function(rule) {
|
||||
@ -74,7 +82,7 @@ DOMElement.prototype = {
|
||||
// Assuming that there is only one matching attribute for a given name,
|
||||
// across all namespaces.
|
||||
if (NS) {
|
||||
var suffix = ':' + name;
|
||||
var suffix = ":" + name;
|
||||
for (var fullName in this.attributes) {
|
||||
if (fullName.slice(-suffix.length) === suffix) {
|
||||
return this.attributes[fullName];
|
||||
@ -85,7 +93,7 @@ DOMElement.prototype = {
|
||||
},
|
||||
|
||||
setAttribute: function DOMElement_setAttribute(name, value) {
|
||||
value = value || '';
|
||||
value = value || "";
|
||||
value = xmlEncode(value);
|
||||
this.attributes[name] = value;
|
||||
},
|
||||
@ -123,7 +131,7 @@ DOMElement.prototype = {
|
||||
while ((chunk = serializer.getNext()) !== null) {
|
||||
buf.push(chunk);
|
||||
}
|
||||
return buf.join('');
|
||||
return buf.join("");
|
||||
},
|
||||
|
||||
getSerializer: function DOMElement_getSerializer() {
|
||||
@ -147,37 +155,39 @@ DOMElementSerializer.prototype = {
|
||||
getNext: function DOMElementSerializer_getNext() {
|
||||
var node = this._node;
|
||||
switch (this._state) {
|
||||
case 0: // Start opening tag.
|
||||
case 0: // Start opening tag.
|
||||
++this._state;
|
||||
return '<' + node.nodeName;
|
||||
case 1: // Add SVG namespace if this is the root element.
|
||||
return "<" + node.nodeName;
|
||||
case 1: // Add SVG namespace if this is the root element.
|
||||
++this._state;
|
||||
if (node.nodeName === 'svg:svg') {
|
||||
return ' xmlns:xlink="http://www.w3.org/1999/xlink"' +
|
||||
' xmlns:svg="http://www.w3.org/2000/svg"';
|
||||
if (node.nodeName === "svg:svg") {
|
||||
return (
|
||||
' xmlns:xlink="http://www.w3.org/1999/xlink"' +
|
||||
' xmlns:svg="http://www.w3.org/2000/svg"'
|
||||
);
|
||||
}
|
||||
/* falls through */
|
||||
case 2: // Initialize variables for looping over attributes.
|
||||
/* falls through */
|
||||
case 2: // Initialize variables for looping over attributes.
|
||||
++this._state;
|
||||
this._loopIndex = 0;
|
||||
this._attributeKeys = Object.keys(node.attributes);
|
||||
/* falls through */
|
||||
case 3: // Serialize any attributes and end opening tag.
|
||||
/* falls through */
|
||||
case 3: // Serialize any attributes and end opening tag.
|
||||
if (this._loopIndex < this._attributeKeys.length) {
|
||||
var name = this._attributeKeys[this._loopIndex++];
|
||||
return ' ' + name + '="' + xmlEncode(node.attributes[name]) + '"';
|
||||
return " " + name + '="' + xmlEncode(node.attributes[name]) + '"';
|
||||
}
|
||||
++this._state;
|
||||
return '>';
|
||||
case 4: // Serialize textContent for tspan/style elements.
|
||||
if (node.nodeName === 'svg:tspan' || node.nodeName === 'svg:style') {
|
||||
return ">";
|
||||
case 4: // Serialize textContent for tspan/style elements.
|
||||
if (node.nodeName === "svg:tspan" || node.nodeName === "svg:style") {
|
||||
this._state = 6;
|
||||
return xmlEncode(node.textContent);
|
||||
}
|
||||
++this._state;
|
||||
this._loopIndex = 0;
|
||||
/* falls through */
|
||||
case 5: // Serialize child nodes (only for non-tspan/style elements).
|
||||
/* falls through */
|
||||
case 5: // Serialize child nodes (only for non-tspan/style elements).
|
||||
var value;
|
||||
while (true) {
|
||||
value = this._childSerializer && this._childSerializer.getNext();
|
||||
@ -193,14 +203,14 @@ DOMElementSerializer.prototype = {
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* falls through */
|
||||
case 6: // Ending tag.
|
||||
/* falls through */
|
||||
case 6: // Ending tag.
|
||||
++this._state;
|
||||
return '</' + node.nodeName + '>';
|
||||
case 7: // Done.
|
||||
return "</" + node.nodeName + ">";
|
||||
case 7: // Done.
|
||||
return null;
|
||||
default:
|
||||
throw new Error('Unexpected serialization state: ' + this._state);
|
||||
throw new Error("Unexpected serialization state: " + this._state);
|
||||
}
|
||||
},
|
||||
};
|
||||
@ -209,7 +219,7 @@ const document = {
|
||||
childNodes: [],
|
||||
|
||||
get currentScript() {
|
||||
return { src: '', };
|
||||
return { src: "" };
|
||||
},
|
||||
|
||||
get documentElement() {
|
||||
@ -222,12 +232,12 @@ const document = {
|
||||
},
|
||||
|
||||
createElement: function(element) {
|
||||
return this.createElementNS('', element);
|
||||
return this.createElementNS("", element);
|
||||
},
|
||||
|
||||
getElementsByTagName: function(element) {
|
||||
if (element === 'head') {
|
||||
return [this.head || (this.head = new DOMElement('head'))];
|
||||
if (element === "head") {
|
||||
return [this.head || (this.head = new DOMElement("head"))];
|
||||
}
|
||||
return [];
|
||||
},
|
||||
@ -256,13 +266,13 @@ var exported_symbols = Object.keys(exports);
|
||||
|
||||
exports.setStubs = function(namespace) {
|
||||
exported_symbols.forEach(function(key) {
|
||||
console.assert(!(key in namespace), 'property should not be set: ' + key);
|
||||
console.assert(!(key in namespace), "property should not be set: " + key);
|
||||
namespace[key] = exports[key];
|
||||
});
|
||||
};
|
||||
exports.unsetStubs = function(namespace) {
|
||||
exported_symbols.forEach(function(key) {
|
||||
console.assert(key in namespace, 'property should be set: ' + key);
|
||||
console.assert(key in namespace, "property should be set: " + key);
|
||||
delete namespace[key];
|
||||
});
|
||||
};
|
||||
|
@ -8,60 +8,68 @@
|
||||
//
|
||||
|
||||
// Run `gulp dist-install` to generate 'pdfjs-dist' npm package files.
|
||||
var pdfjsLib = require('pdfjs-dist');
|
||||
var pdfjsLib = require("pdfjs-dist");
|
||||
|
||||
// Loading file from file system into typed array
|
||||
var pdfPath = process.argv[2] || '../../web/compressed.tracemonkey-pldi-09.pdf';
|
||||
var pdfPath = process.argv[2] || "../../web/compressed.tracemonkey-pldi-09.pdf";
|
||||
|
||||
// Will be using promises to load document, pages and misc data instead of
|
||||
// callback.
|
||||
var loadingTask = pdfjsLib.getDocument(pdfPath);
|
||||
loadingTask.promise.then(function(doc) {
|
||||
var numPages = doc.numPages;
|
||||
console.log('# Document Loaded');
|
||||
console.log('Number of Pages: ' + numPages);
|
||||
console.log();
|
||||
|
||||
var lastPromise; // will be used to chain promises
|
||||
lastPromise = doc.getMetadata().then(function (data) {
|
||||
console.log('# Metadata Is Loaded');
|
||||
console.log('## Info');
|
||||
console.log(JSON.stringify(data.info, null, 2));
|
||||
loadingTask.promise
|
||||
.then(function(doc) {
|
||||
var numPages = doc.numPages;
|
||||
console.log("# Document Loaded");
|
||||
console.log("Number of Pages: " + numPages);
|
||||
console.log();
|
||||
if (data.metadata) {
|
||||
console.log('## Metadata');
|
||||
console.log(JSON.stringify(data.metadata.getAll(), null, 2));
|
||||
console.log();
|
||||
}
|
||||
});
|
||||
|
||||
var loadPage = function (pageNum) {
|
||||
return doc.getPage(pageNum).then(function (page) {
|
||||
console.log('# Page ' + pageNum);
|
||||
var viewport = page.getViewport({ scale: 1.0, });
|
||||
console.log('Size: ' + viewport.width + 'x' + viewport.height);
|
||||
var lastPromise; // will be used to chain promises
|
||||
lastPromise = doc.getMetadata().then(function(data) {
|
||||
console.log("# Metadata Is Loaded");
|
||||
console.log("## Info");
|
||||
console.log(JSON.stringify(data.info, null, 2));
|
||||
console.log();
|
||||
return page.getTextContent().then(function (content) {
|
||||
// Content contains lots of information about the text layout and
|
||||
// styles, but we need only strings at the moment
|
||||
var strings = content.items.map(function (item) {
|
||||
return item.str;
|
||||
});
|
||||
console.log('## Text Content');
|
||||
console.log(strings.join(' '));
|
||||
}).then(function () {
|
||||
if (data.metadata) {
|
||||
console.log("## Metadata");
|
||||
console.log(JSON.stringify(data.metadata.getAll(), null, 2));
|
||||
console.log();
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
// Loading of the first page will wait on metadata and subsequent loadings
|
||||
// will wait on the previous pages.
|
||||
for (var i = 1; i <= numPages; i++) {
|
||||
lastPromise = lastPromise.then(loadPage.bind(null, i));
|
||||
}
|
||||
return lastPromise;
|
||||
}).then(function () {
|
||||
console.log('# End of Document');
|
||||
}, function (err) {
|
||||
console.error('Error: ' + err);
|
||||
});
|
||||
|
||||
var loadPage = function(pageNum) {
|
||||
return doc.getPage(pageNum).then(function(page) {
|
||||
console.log("# Page " + pageNum);
|
||||
var viewport = page.getViewport({ scale: 1.0 });
|
||||
console.log("Size: " + viewport.width + "x" + viewport.height);
|
||||
console.log();
|
||||
return page
|
||||
.getTextContent()
|
||||
.then(function(content) {
|
||||
// Content contains lots of information about the text layout and
|
||||
// styles, but we need only strings at the moment
|
||||
var strings = content.items.map(function(item) {
|
||||
return item.str;
|
||||
});
|
||||
console.log("## Text Content");
|
||||
console.log(strings.join(" "));
|
||||
})
|
||||
.then(function() {
|
||||
console.log();
|
||||
});
|
||||
});
|
||||
};
|
||||
// Loading of the first page will wait on metadata and subsequent loadings
|
||||
// will wait on the previous pages.
|
||||
for (var i = 1; i <= numPages; i++) {
|
||||
lastPromise = lastPromise.then(loadPage.bind(null, i));
|
||||
}
|
||||
return lastPromise;
|
||||
})
|
||||
.then(
|
||||
function() {
|
||||
console.log("# End of Document");
|
||||
},
|
||||
function(err) {
|
||||
console.error("Error: " + err);
|
||||
}
|
||||
);
|
||||
|
@ -13,16 +13,16 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
var Canvas = require('canvas');
|
||||
var assert = require('assert').strict;
|
||||
var fs = require('fs');
|
||||
var Canvas = require("canvas");
|
||||
var assert = require("assert").strict;
|
||||
var fs = require("fs");
|
||||
|
||||
function NodeCanvasFactory() {}
|
||||
NodeCanvasFactory.prototype = {
|
||||
create: function NodeCanvasFactory_create(width, height) {
|
||||
assert(width > 0 && height > 0, 'Invalid canvas size');
|
||||
assert(width > 0 && height > 0, "Invalid canvas size");
|
||||
var canvas = Canvas.createCanvas(width, height);
|
||||
var context = canvas.getContext('2d');
|
||||
var context = canvas.getContext("2d");
|
||||
return {
|
||||
canvas: canvas,
|
||||
context: context,
|
||||
@ -30,14 +30,14 @@ NodeCanvasFactory.prototype = {
|
||||
},
|
||||
|
||||
reset: function NodeCanvasFactory_reset(canvasAndContext, width, height) {
|
||||
assert(canvasAndContext.canvas, 'Canvas is not specified');
|
||||
assert(width > 0 && height > 0, 'Invalid canvas size');
|
||||
assert(canvasAndContext.canvas, "Canvas is not specified");
|
||||
assert(width > 0 && height > 0, "Invalid canvas size");
|
||||
canvasAndContext.canvas.width = width;
|
||||
canvasAndContext.canvas.height = height;
|
||||
},
|
||||
|
||||
destroy: function NodeCanvasFactory_destroy(canvasAndContext) {
|
||||
assert(canvasAndContext.canvas, 'Canvas is not specified');
|
||||
assert(canvasAndContext.canvas, "Canvas is not specified");
|
||||
|
||||
// Zeroing the width and height cause Firefox to release graphics
|
||||
// resources immediately, which can greatly reduce memory consumption.
|
||||
@ -48,46 +48,51 @@ NodeCanvasFactory.prototype = {
|
||||
},
|
||||
};
|
||||
|
||||
var pdfjsLib = require('pdfjs-dist');
|
||||
var pdfjsLib = require("pdfjs-dist");
|
||||
|
||||
// Relative path of the PDF file.
|
||||
var pdfURL = '../../../web/compressed.tracemonkey-pldi-09.pdf';
|
||||
var pdfURL = "../../../web/compressed.tracemonkey-pldi-09.pdf";
|
||||
|
||||
// Read the PDF file into a typed array so PDF.js can load it.
|
||||
var rawData = new Uint8Array(fs.readFileSync(pdfURL));
|
||||
|
||||
// Load the PDF file.
|
||||
var loadingTask = pdfjsLib.getDocument(rawData);
|
||||
loadingTask.promise.then(function(pdfDocument) {
|
||||
console.log('# PDF document loaded.');
|
||||
loadingTask.promise
|
||||
.then(function(pdfDocument) {
|
||||
console.log("# PDF document loaded.");
|
||||
|
||||
// Get the first page.
|
||||
pdfDocument.getPage(1).then(function (page) {
|
||||
// Render the page on a Node canvas with 100% scale.
|
||||
var viewport = page.getViewport({ scale: 1.0, });
|
||||
var canvasFactory = new NodeCanvasFactory();
|
||||
var canvasAndContext =
|
||||
canvasFactory.create(viewport.width, viewport.height);
|
||||
var renderContext = {
|
||||
canvasContext: canvasAndContext.context,
|
||||
viewport: viewport,
|
||||
canvasFactory: canvasFactory,
|
||||
};
|
||||
// Get the first page.
|
||||
pdfDocument.getPage(1).then(function(page) {
|
||||
// Render the page on a Node canvas with 100% scale.
|
||||
var viewport = page.getViewport({ scale: 1.0 });
|
||||
var canvasFactory = new NodeCanvasFactory();
|
||||
var canvasAndContext = canvasFactory.create(
|
||||
viewport.width,
|
||||
viewport.height
|
||||
);
|
||||
var renderContext = {
|
||||
canvasContext: canvasAndContext.context,
|
||||
viewport: viewport,
|
||||
canvasFactory: canvasFactory,
|
||||
};
|
||||
|
||||
var renderTask = page.render(renderContext);
|
||||
renderTask.promise.then(function() {
|
||||
// Convert the canvas to an image buffer.
|
||||
var image = canvasAndContext.canvas.toBuffer();
|
||||
fs.writeFile('output.png', image, function (error) {
|
||||
if (error) {
|
||||
console.error('Error: ' + error);
|
||||
} else {
|
||||
console.log(
|
||||
'Finished converting first page of PDF file to a PNG image.');
|
||||
}
|
||||
var renderTask = page.render(renderContext);
|
||||
renderTask.promise.then(function() {
|
||||
// Convert the canvas to an image buffer.
|
||||
var image = canvasAndContext.canvas.toBuffer();
|
||||
fs.writeFile("output.png", image, function(error) {
|
||||
if (error) {
|
||||
console.error("Error: " + error);
|
||||
} else {
|
||||
console.log(
|
||||
"Finished converting first page of PDF file to a PNG image."
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
})
|
||||
.catch(function(reason) {
|
||||
console.log(reason);
|
||||
});
|
||||
}).catch(function(reason) {
|
||||
console.log(reason);
|
||||
});
|
||||
|
@ -5,29 +5,29 @@
|
||||
// Node tool to dump SVG output into a file.
|
||||
//
|
||||
|
||||
var fs = require('fs');
|
||||
var util = require('util');
|
||||
var path = require('path');
|
||||
var stream = require('stream');
|
||||
var fs = require("fs");
|
||||
var util = require("util");
|
||||
var path = require("path");
|
||||
var stream = require("stream");
|
||||
|
||||
// HACK few hacks to let PDF.js be loaded not as a module in global space.
|
||||
require('./domstubs.js').setStubs(global);
|
||||
require("./domstubs.js").setStubs(global);
|
||||
|
||||
// Run `gulp dist-install` to generate 'pdfjs-dist' npm package files.
|
||||
var pdfjsLib = require('pdfjs-dist');
|
||||
var pdfjsLib = require("pdfjs-dist");
|
||||
|
||||
// Loading file from file system into typed array
|
||||
var pdfPath = process.argv[2] || '../../web/compressed.tracemonkey-pldi-09.pdf';
|
||||
var pdfPath = process.argv[2] || "../../web/compressed.tracemonkey-pldi-09.pdf";
|
||||
var data = new Uint8Array(fs.readFileSync(pdfPath));
|
||||
|
||||
var outputDirectory = './svgdump';
|
||||
var outputDirectory = "./svgdump";
|
||||
|
||||
try {
|
||||
// Note: This creates a directory only one level deep. If you want to create
|
||||
// multiple subdirectories on the fly, use the mkdirp module from npm.
|
||||
fs.mkdirSync(outputDirectory);
|
||||
} catch (e) {
|
||||
if (e.code !== 'EEXIST') {
|
||||
if (e.code !== "EEXIST") {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
@ -35,7 +35,7 @@ try {
|
||||
// Dumps svg outputs to a folder called svgdump
|
||||
function getFilePathForPage(pageNum) {
|
||||
var name = path.basename(pdfPath, path.extname(pdfPath));
|
||||
return path.join(outputDirectory, name + '-' + pageNum + '.svg');
|
||||
return path.join(outputDirectory, name + "-" + pageNum + ".svg");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -71,9 +71,9 @@ function writeSvgToFile(svgElement, filePath) {
|
||||
});
|
||||
var writableStream = fs.createWriteStream(filePath);
|
||||
return new Promise(function(resolve, reject) {
|
||||
readableSvgStream.once('error', reject);
|
||||
writableStream.once('error', reject);
|
||||
writableStream.once('finish', resolve);
|
||||
readableSvgStream.once("error", reject);
|
||||
writableStream.once("error", reject);
|
||||
writableStream.once("finish", resolve);
|
||||
readableSvgStream.pipe(writableStream);
|
||||
}).catch(function(err) {
|
||||
readableSvgStream = null; // Explicitly null because of v8 bug 6512.
|
||||
@ -90,41 +90,48 @@ var loadingTask = pdfjsLib.getDocument({
|
||||
// processing.
|
||||
nativeImageDecoderSupport: pdfjsLib.NativeImageDecoding.DISPLAY,
|
||||
});
|
||||
loadingTask.promise.then(function(doc) {
|
||||
var numPages = doc.numPages;
|
||||
console.log('# Document Loaded');
|
||||
console.log('Number of Pages: ' + numPages);
|
||||
console.log();
|
||||
loadingTask.promise
|
||||
.then(function(doc) {
|
||||
var numPages = doc.numPages;
|
||||
console.log("# Document Loaded");
|
||||
console.log("Number of Pages: " + numPages);
|
||||
console.log();
|
||||
|
||||
var lastPromise = Promise.resolve(); // will be used to chain promises
|
||||
var loadPage = function (pageNum) {
|
||||
return doc.getPage(pageNum).then(function (page) {
|
||||
console.log('# Page ' + pageNum);
|
||||
var viewport = page.getViewport({ scale: 1.0, });
|
||||
console.log('Size: ' + viewport.width + 'x' + viewport.height);
|
||||
console.log();
|
||||
var lastPromise = Promise.resolve(); // will be used to chain promises
|
||||
var loadPage = function(pageNum) {
|
||||
return doc.getPage(pageNum).then(function(page) {
|
||||
console.log("# Page " + pageNum);
|
||||
var viewport = page.getViewport({ scale: 1.0 });
|
||||
console.log("Size: " + viewport.width + "x" + viewport.height);
|
||||
console.log();
|
||||
|
||||
return page.getOperatorList().then(function (opList) {
|
||||
var svgGfx = new pdfjsLib.SVGGraphics(page.commonObjs, page.objs);
|
||||
svgGfx.embedFonts = true;
|
||||
return svgGfx.getSVG(opList, viewport).then(function (svg) {
|
||||
return writeSvgToFile(svg, getFilePathForPage(pageNum))
|
||||
.then(function () {
|
||||
console.log('Page: ' + pageNum);
|
||||
}, function(err) {
|
||||
console.log('Error: ' + err);
|
||||
});
|
||||
return page.getOperatorList().then(function(opList) {
|
||||
var svgGfx = new pdfjsLib.SVGGraphics(page.commonObjs, page.objs);
|
||||
svgGfx.embedFonts = true;
|
||||
return svgGfx.getSVG(opList, viewport).then(function(svg) {
|
||||
return writeSvgToFile(svg, getFilePathForPage(pageNum)).then(
|
||||
function() {
|
||||
console.log("Page: " + pageNum);
|
||||
},
|
||||
function(err) {
|
||||
console.log("Error: " + err);
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
for (var i = 1; i <= numPages; i++) {
|
||||
lastPromise = lastPromise.then(loadPage.bind(null, i));
|
||||
}
|
||||
return lastPromise;
|
||||
}).then(function () {
|
||||
console.log('# End of Document');
|
||||
}, function (err) {
|
||||
console.error('Error: ' + err);
|
||||
});
|
||||
for (var i = 1; i <= numPages; i++) {
|
||||
lastPromise = lastPromise.then(loadPage.bind(null, i));
|
||||
}
|
||||
return lastPromise;
|
||||
})
|
||||
.then(
|
||||
function() {
|
||||
console.log("# End of Document");
|
||||
},
|
||||
function(err) {
|
||||
console.error("Error: " + err);
|
||||
}
|
||||
);
|
||||
|
@ -13,26 +13,25 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
"use strict";
|
||||
|
||||
if (!pdfjsLib.getDocument || !pdfjsViewer.PDFViewer) {
|
||||
alert('Please build the pdfjs-dist library using\n' +
|
||||
' `gulp dist-install`');
|
||||
alert("Please build the pdfjs-dist library using\n `gulp dist-install`");
|
||||
}
|
||||
|
||||
// The workerSrc property shall be specified.
|
||||
//
|
||||
pdfjsLib.GlobalWorkerOptions.workerSrc =
|
||||
'../../node_modules/pdfjs-dist/build/pdf.worker.js';
|
||||
"../../node_modules/pdfjs-dist/build/pdf.worker.js";
|
||||
|
||||
// Some PDFs need external cmaps.
|
||||
//
|
||||
var CMAP_URL = '../../node_modules/pdfjs-dist/cmaps/';
|
||||
var CMAP_URL = "../../node_modules/pdfjs-dist/cmaps/";
|
||||
var CMAP_PACKED = true;
|
||||
|
||||
var DEFAULT_URL = '../../web/compressed.tracemonkey-pldi-09.pdf';
|
||||
var DEFAULT_URL = "../../web/compressed.tracemonkey-pldi-09.pdf";
|
||||
|
||||
var container = document.getElementById('viewerContainer');
|
||||
var container = document.getElementById("viewerContainer");
|
||||
|
||||
// (Optionally) enable hyperlinks within PDF files.
|
||||
var pdfLinkService = new pdfjsViewer.PDFLinkService();
|
||||
@ -40,14 +39,14 @@ var pdfLinkService = new pdfjsViewer.PDFLinkService();
|
||||
var pdfViewer = new pdfjsViewer.PDFViewer({
|
||||
container: container,
|
||||
linkService: pdfLinkService,
|
||||
renderer: 'svg',
|
||||
renderer: "svg",
|
||||
textLayerMode: 0,
|
||||
});
|
||||
pdfLinkService.setViewer(pdfViewer);
|
||||
|
||||
document.addEventListener('pagesinit', function () {
|
||||
document.addEventListener("pagesinit", function() {
|
||||
// We can use pdfViewer now, e.g. let's change default scale.
|
||||
pdfViewer.currentScaleValue = 'page-width';
|
||||
pdfViewer.currentScaleValue = "page-width";
|
||||
});
|
||||
|
||||
// Loading document.
|
||||
|
@ -13,34 +13,35 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
var PDF_PATH = '../../web/compressed.tracemonkey-pldi-09.pdf';
|
||||
var PDF_PATH = "../../web/compressed.tracemonkey-pldi-09.pdf";
|
||||
var PAGE_NUMBER = 1;
|
||||
var PAGE_SCALE = 1.5;
|
||||
var SVG_NS = 'http://www.w3.org/2000/svg';
|
||||
var SVG_NS = "http://www.w3.org/2000/svg";
|
||||
|
||||
pdfjsLib.GlobalWorkerOptions.workerSrc =
|
||||
'../../node_modules/pdfjs-dist/build/pdf.worker.js';
|
||||
"../../node_modules/pdfjs-dist/build/pdf.worker.js";
|
||||
|
||||
function buildSVG(viewport, textContent) {
|
||||
// Building SVG with size of the viewport (for simplicity)
|
||||
var svg = document.createElementNS(SVG_NS, 'svg:svg');
|
||||
svg.setAttribute('width', viewport.width + 'px');
|
||||
svg.setAttribute('height', viewport.height + 'px');
|
||||
var svg = document.createElementNS(SVG_NS, "svg:svg");
|
||||
svg.setAttribute("width", viewport.width + "px");
|
||||
svg.setAttribute("height", viewport.height + "px");
|
||||
// items are transformed to have 1px font size
|
||||
svg.setAttribute('font-size', 1);
|
||||
svg.setAttribute("font-size", 1);
|
||||
|
||||
// processing all items
|
||||
textContent.items.forEach(function (textItem) {
|
||||
textContent.items.forEach(function(textItem) {
|
||||
// we have to take in account viewport transform, which includes scale,
|
||||
// rotation and Y-axis flip, and not forgetting to flip text.
|
||||
var tx = pdfjsLib.Util.transform(
|
||||
pdfjsLib.Util.transform(viewport.transform, textItem.transform),
|
||||
[1, 0, 0, -1, 0, 0]);
|
||||
[1, 0, 0, -1, 0, 0]
|
||||
);
|
||||
var style = textContent.styles[textItem.fontName];
|
||||
// adding text element
|
||||
var text = document.createElementNS(SVG_NS, 'svg:text');
|
||||
text.setAttribute('transform', 'matrix(' + tx.join(' ') + ')');
|
||||
text.setAttribute('font-family', style.fontFamily);
|
||||
var text = document.createElementNS(SVG_NS, "svg:text");
|
||||
text.setAttribute("transform", "matrix(" + tx.join(" ") + ")");
|
||||
text.setAttribute("font-family", style.fontFamily);
|
||||
text.textContent = textItem.str;
|
||||
svg.appendChild(text);
|
||||
});
|
||||
@ -49,23 +50,25 @@ function buildSVG(viewport, textContent) {
|
||||
|
||||
function pageLoaded() {
|
||||
// Loading document and page text content
|
||||
var loadingTask = pdfjsLib.getDocument({ url: PDF_PATH, });
|
||||
var loadingTask = pdfjsLib.getDocument({ url: PDF_PATH });
|
||||
loadingTask.promise.then(function(pdfDocument) {
|
||||
pdfDocument.getPage(PAGE_NUMBER).then(function (page) {
|
||||
var viewport = page.getViewport({ scale: PAGE_SCALE, });
|
||||
page.getTextContent().then(function (textContent) {
|
||||
pdfDocument.getPage(PAGE_NUMBER).then(function(page) {
|
||||
var viewport = page.getViewport({ scale: PAGE_SCALE });
|
||||
page.getTextContent().then(function(textContent) {
|
||||
// building SVG and adding that to the DOM
|
||||
var svg = buildSVG(viewport, textContent);
|
||||
document.getElementById('pageContainer').appendChild(svg);
|
||||
document.getElementById("pageContainer").appendChild(svg);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
if (typeof pdfjsLib === 'undefined') {
|
||||
alert('Built version of PDF.js was not found.\n' +
|
||||
'Please run `gulp dist-install`.');
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
if (typeof pdfjsLib === "undefined") {
|
||||
alert(
|
||||
"Built version of PDF.js was not found.\n" +
|
||||
"Please run `gulp dist-install`."
|
||||
);
|
||||
return;
|
||||
}
|
||||
pageLoaded();
|
||||
|
@ -3,31 +3,33 @@
|
||||
|
||||
// Hello world example for webpack.
|
||||
|
||||
var pdfjsLib = require('pdfjs-dist');
|
||||
var pdfjsLib = require("pdfjs-dist");
|
||||
|
||||
var pdfPath = '../learning/helloworld.pdf';
|
||||
var pdfPath = "../learning/helloworld.pdf";
|
||||
|
||||
// Setting worker path to worker bundle.
|
||||
pdfjsLib.GlobalWorkerOptions.workerSrc =
|
||||
'../../build/webpack/pdf.worker.bundle.js';
|
||||
"../../build/webpack/pdf.worker.bundle.js";
|
||||
|
||||
// Loading a document.
|
||||
var loadingTask = pdfjsLib.getDocument(pdfPath);
|
||||
loadingTask.promise.then(function (pdfDocument) {
|
||||
// Request a first page
|
||||
return pdfDocument.getPage(1).then(function (pdfPage) {
|
||||
// Display page on the existing canvas with 100% scale.
|
||||
var viewport = pdfPage.getViewport({ scale: 1.0, });
|
||||
var canvas = document.getElementById('theCanvas');
|
||||
canvas.width = viewport.width;
|
||||
canvas.height = viewport.height;
|
||||
var ctx = canvas.getContext('2d');
|
||||
var renderTask = pdfPage.render({
|
||||
canvasContext: ctx,
|
||||
viewport: viewport,
|
||||
loadingTask.promise
|
||||
.then(function(pdfDocument) {
|
||||
// Request a first page
|
||||
return pdfDocument.getPage(1).then(function(pdfPage) {
|
||||
// Display page on the existing canvas with 100% scale.
|
||||
var viewport = pdfPage.getViewport({ scale: 1.0 });
|
||||
var canvas = document.getElementById("theCanvas");
|
||||
canvas.width = viewport.width;
|
||||
canvas.height = viewport.height;
|
||||
var ctx = canvas.getContext("2d");
|
||||
var renderTask = pdfPage.render({
|
||||
canvasContext: ctx,
|
||||
viewport: viewport,
|
||||
});
|
||||
return renderTask.promise;
|
||||
});
|
||||
return renderTask.promise;
|
||||
})
|
||||
.catch(function(reason) {
|
||||
console.error("Error: " + reason);
|
||||
});
|
||||
}).catch(function (reason) {
|
||||
console.error('Error: ' + reason);
|
||||
});
|
||||
|
@ -1,16 +1,16 @@
|
||||
var webpack = require('webpack'); // eslint-disable-line no-unused-vars
|
||||
var path = require('path');
|
||||
var webpack = require("webpack"); // eslint-disable-line no-unused-vars
|
||||
var path = require("path");
|
||||
|
||||
module.exports = {
|
||||
context: __dirname,
|
||||
entry: {
|
||||
'main': './main.js',
|
||||
'pdf.worker': 'pdfjs-dist/build/pdf.worker.entry',
|
||||
main: "./main.js",
|
||||
"pdf.worker": "pdfjs-dist/build/pdf.worker.entry",
|
||||
},
|
||||
mode: 'none',
|
||||
mode: "none",
|
||||
output: {
|
||||
path: path.join(__dirname, '../../build/webpack'),
|
||||
publicPath: '../../build/webpack/',
|
||||
filename: '[name].bundle.js',
|
||||
path: path.join(__dirname, "../../build/webpack"),
|
||||
publicPath: "../../build/webpack/",
|
||||
filename: "[name].bundle.js",
|
||||
},
|
||||
};
|
||||
|
@ -14,22 +14,22 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
"use strict";
|
||||
|
||||
var VIEWER_URL = chrome.extension.getURL('content/web/viewer.html');
|
||||
var VIEWER_URL = chrome.extension.getURL("content/web/viewer.html");
|
||||
|
||||
function getViewerURL(pdf_url) {
|
||||
return VIEWER_URL + '?file=' + encodeURIComponent(pdf_url);
|
||||
return VIEWER_URL + "?file=" + encodeURIComponent(pdf_url);
|
||||
}
|
||||
|
||||
if (CSS.supports('animation', '0s')) {
|
||||
document.addEventListener('animationstart', onAnimationStart, true);
|
||||
if (CSS.supports("animation", "0s")) {
|
||||
document.addEventListener("animationstart", onAnimationStart, true);
|
||||
} else {
|
||||
document.addEventListener('webkitAnimationStart', onAnimationStart, true);
|
||||
document.addEventListener("webkitAnimationStart", onAnimationStart, true);
|
||||
}
|
||||
|
||||
function onAnimationStart(event) {
|
||||
if (event.animationName === 'pdfjs-detected-object-or-embed') {
|
||||
if (event.animationName === "pdfjs-detected-object-or-embed") {
|
||||
watchObjectOrEmbed(event.target);
|
||||
}
|
||||
}
|
||||
@ -40,19 +40,23 @@ function onAnimationStart(event) {
|
||||
// invocations have no effect.
|
||||
function watchObjectOrEmbed(elem) {
|
||||
var mimeType = elem.type;
|
||||
if (mimeType && mimeType.toLowerCase() !== 'application/pdf') {
|
||||
if (mimeType && mimeType.toLowerCase() !== "application/pdf") {
|
||||
return;
|
||||
}
|
||||
// <embed src> <object data>
|
||||
var srcAttribute = 'src' in elem ? 'src' : 'data';
|
||||
var srcAttribute = "src" in elem ? "src" : "data";
|
||||
var path = elem[srcAttribute];
|
||||
if (!mimeType && !/\.pdf($|[?#])/i.test(path)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (elem.tagName === 'EMBED' && elem.name === 'plugin' &&
|
||||
elem.parentNode === document.body &&
|
||||
elem.parentNode.childElementCount === 1 && elem.src === location.href) {
|
||||
if (
|
||||
elem.tagName === "EMBED" &&
|
||||
elem.name === "plugin" &&
|
||||
elem.parentNode === document.body &&
|
||||
elem.parentNode.childElementCount === 1 &&
|
||||
elem.src === location.href
|
||||
) {
|
||||
// This page is most likely Chrome's default page that embeds a PDF file.
|
||||
// The fact that the extension's background page did not intercept and
|
||||
// redirect this PDF request means that this PDF cannot be opened by PDF.js,
|
||||
@ -62,7 +66,7 @@ function watchObjectOrEmbed(elem) {
|
||||
// Until #4483 is fixed, POST requests should be ignored.
|
||||
return;
|
||||
}
|
||||
if (elem.tagName === 'EMBED' && elem.src === 'about:blank') {
|
||||
if (elem.tagName === "EMBED" && elem.src === "about:blank") {
|
||||
// Starting from Chrome 76, internal embeds do not have the original URL,
|
||||
// but "about:blank" instead.
|
||||
// See https://github.com/mozilla/pdf.js/issues/11137
|
||||
@ -76,9 +80,9 @@ function watchObjectOrEmbed(elem) {
|
||||
|
||||
var tagName = elem.tagName.toUpperCase();
|
||||
var updateEmbedOrObject;
|
||||
if (tagName === 'EMBED') {
|
||||
if (tagName === "EMBED") {
|
||||
updateEmbedOrObject = updateEmbedElement;
|
||||
} else if (tagName === 'OBJECT') {
|
||||
} else if (tagName === "OBJECT") {
|
||||
updateEmbedOrObject = updateObjectElement;
|
||||
} else {
|
||||
return;
|
||||
@ -115,7 +119,7 @@ function watchObjectOrEmbed(elem) {
|
||||
|
||||
// Display the PDF Viewer in an <embed>.
|
||||
function updateEmbedElement(elem) {
|
||||
if (elem.type === 'text/html' && elem.src.lastIndexOf(VIEWER_URL, 0) === 0) {
|
||||
if (elem.type === "text/html" && elem.src.lastIndexOf(VIEWER_URL, 0) === 0) {
|
||||
// The viewer is already shown.
|
||||
return;
|
||||
}
|
||||
@ -126,7 +130,7 @@ function updateEmbedElement(elem) {
|
||||
if (parentNode) {
|
||||
parentNode.removeChild(elem);
|
||||
}
|
||||
elem.type = 'text/html';
|
||||
elem.type = "text/html";
|
||||
elem.src = getEmbeddedViewerURL(elem.src);
|
||||
if (parentNode) {
|
||||
parentNode.insertBefore(elem, nextSibling);
|
||||
@ -155,21 +159,21 @@ function updateObjectElement(elem) {
|
||||
var iframe = elem.firstElementChild;
|
||||
if (!iframe || !iframe.__inserted_by_pdfjs) {
|
||||
iframe = createFullSizeIframe();
|
||||
elem.textContent = '';
|
||||
elem.textContent = "";
|
||||
elem.appendChild(iframe);
|
||||
iframe.__inserted_by_pdfjs = true;
|
||||
}
|
||||
iframe.src = getEmbeddedViewerURL(elem.data);
|
||||
|
||||
// Some bogus content type that is not handled by any plugin.
|
||||
elem.type = 'application/not-a-pee-dee-eff-type';
|
||||
elem.type = "application/not-a-pee-dee-eff-type";
|
||||
// Force the <object> to reload and render its fallback content.
|
||||
elem.data += '';
|
||||
elem.data += "";
|
||||
|
||||
// Usually the browser renders plugin content in this tag, which is completely
|
||||
// oblivious of styles such as padding, but we insert and render child nodes,
|
||||
// so force padding to be zero to avoid undesired dimension changes.
|
||||
elem.style.padding = '0';
|
||||
elem.style.padding = "0";
|
||||
|
||||
// <object> and <embed> elements have a "display:inline" style by default.
|
||||
// Despite this property, when a plugin is loaded in the tag, the tag is
|
||||
@ -180,27 +184,27 @@ function updateObjectElement(elem) {
|
||||
// web pages is respected.
|
||||
// (<embed> behaves as expected with the default display value, but setting it
|
||||
// to display:inline-block doesn't hurt).
|
||||
elem.style.display = 'inline-block';
|
||||
elem.style.display = "inline-block";
|
||||
}
|
||||
|
||||
// Create an <iframe> element without borders that takes the full width and
|
||||
// height.
|
||||
function createFullSizeIframe() {
|
||||
var iframe = document.createElement('iframe');
|
||||
iframe.style.background = 'none';
|
||||
iframe.style.border = 'none';
|
||||
iframe.style.borderRadius = 'none';
|
||||
iframe.style.boxShadow = 'none';
|
||||
iframe.style.cssFloat = 'none';
|
||||
iframe.style.display = 'block';
|
||||
iframe.style.height = '100%';
|
||||
iframe.style.margin = '0';
|
||||
iframe.style.maxHeight = 'none';
|
||||
iframe.style.maxWidth = 'none';
|
||||
iframe.style.position = 'static';
|
||||
iframe.style.transform = 'none';
|
||||
iframe.style.visibility = 'visible';
|
||||
iframe.style.width = '100%';
|
||||
var iframe = document.createElement("iframe");
|
||||
iframe.style.background = "none";
|
||||
iframe.style.border = "none";
|
||||
iframe.style.borderRadius = "none";
|
||||
iframe.style.boxShadow = "none";
|
||||
iframe.style.cssFloat = "none";
|
||||
iframe.style.display = "block";
|
||||
iframe.style.height = "100%";
|
||||
iframe.style.margin = "0";
|
||||
iframe.style.maxHeight = "none";
|
||||
iframe.style.maxWidth = "none";
|
||||
iframe.style.position = "static";
|
||||
iframe.style.transform = "none";
|
||||
iframe.style.visibility = "visible";
|
||||
iframe.style.width = "100%";
|
||||
return iframe;
|
||||
}
|
||||
|
||||
@ -208,10 +212,10 @@ function createFullSizeIframe() {
|
||||
function getEmbeddedViewerURL(path) {
|
||||
var fragment = /^([^#]*)(#.*)?$/.exec(path);
|
||||
path = fragment[1];
|
||||
fragment = fragment[2] || '';
|
||||
fragment = fragment[2] || "";
|
||||
|
||||
// Resolve relative path to document.
|
||||
var a = document.createElement('a');
|
||||
var a = document.createElement("a");
|
||||
a.href = document.baseURI;
|
||||
a.href = path;
|
||||
path = a.href;
|
||||
|
@ -14,24 +14,24 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
"use strict";
|
||||
|
||||
(function ExtensionRouterClosure() {
|
||||
var VIEWER_URL = chrome.extension.getURL('content/web/viewer.html');
|
||||
var CRX_BASE_URL = chrome.extension.getURL('/');
|
||||
var VIEWER_URL = chrome.extension.getURL("content/web/viewer.html");
|
||||
var CRX_BASE_URL = chrome.extension.getURL("/");
|
||||
|
||||
var schemes = [
|
||||
'http',
|
||||
'https',
|
||||
'ftp',
|
||||
'file',
|
||||
'chrome-extension',
|
||||
'blob',
|
||||
'data',
|
||||
"http",
|
||||
"https",
|
||||
"ftp",
|
||||
"file",
|
||||
"chrome-extension",
|
||||
"blob",
|
||||
"data",
|
||||
// Chromium OS
|
||||
'filesystem',
|
||||
"filesystem",
|
||||
// Chromium OS, shorthand for filesystem:<origin>/external/
|
||||
'drive'
|
||||
"drive",
|
||||
];
|
||||
|
||||
/**
|
||||
@ -47,8 +47,8 @@ limitations under the License.
|
||||
}
|
||||
var scheme = url.slice(0, schemeIndex).toLowerCase();
|
||||
if (schemes.includes(scheme)) {
|
||||
url = url.split('#')[0];
|
||||
if (url.charAt(schemeIndex) === ':') {
|
||||
url = url.split("#")[0];
|
||||
if (url.charAt(schemeIndex) === ":") {
|
||||
url = encodeURIComponent(url);
|
||||
}
|
||||
return url;
|
||||
@ -60,55 +60,65 @@ limitations under the License.
|
||||
// supported, see http://crbug.com/273589
|
||||
// (or rewrite the query string parser in viewer.js to get it to
|
||||
// recognize the non-URL-encoded PDF URL.)
|
||||
chrome.webRequest.onBeforeRequest.addListener(function(details) {
|
||||
// This listener converts chrome-extension://.../http://...pdf to
|
||||
// chrome-extension://.../content/web/viewer.html?file=http%3A%2F%2F...pdf
|
||||
var url = parseExtensionURL(details.url);
|
||||
if (url) {
|
||||
url = VIEWER_URL + '?file=' + url;
|
||||
var i = details.url.indexOf('#');
|
||||
if (i > 0) {
|
||||
url += details.url.slice(i);
|
||||
chrome.webRequest.onBeforeRequest.addListener(
|
||||
function(details) {
|
||||
// This listener converts chrome-extension://.../http://...pdf to
|
||||
// chrome-extension://.../content/web/viewer.html?file=http%3A%2F%2F...pdf
|
||||
var url = parseExtensionURL(details.url);
|
||||
if (url) {
|
||||
url = VIEWER_URL + "?file=" + url;
|
||||
var i = details.url.indexOf("#");
|
||||
if (i > 0) {
|
||||
url += details.url.slice(i);
|
||||
}
|
||||
console.log("Redirecting " + details.url + " to " + url);
|
||||
return { redirectUrl: url };
|
||||
}
|
||||
console.log('Redirecting ' + details.url + ' to ' + url);
|
||||
return { redirectUrl: url, };
|
||||
}
|
||||
return undefined;
|
||||
}, {
|
||||
types: ['main_frame', 'sub_frame'],
|
||||
urls: schemes.map(function(scheme) {
|
||||
// Format: "chrome-extension://[EXTENSIONID]/<scheme>*"
|
||||
return CRX_BASE_URL + scheme + '*';
|
||||
}),
|
||||
}, ['blocking']);
|
||||
return undefined;
|
||||
},
|
||||
{
|
||||
types: ["main_frame", "sub_frame"],
|
||||
urls: schemes.map(function(scheme) {
|
||||
// Format: "chrome-extension://[EXTENSIONID]/<scheme>*"
|
||||
return CRX_BASE_URL + scheme + "*";
|
||||
}),
|
||||
},
|
||||
["blocking"]
|
||||
);
|
||||
|
||||
// When session restore is used, viewer pages may be loaded before the
|
||||
// webRequest event listener is attached (= page not found).
|
||||
// Or the extension could have been crashed (OOM), leaving a sad tab behind.
|
||||
// Reload these tabs.
|
||||
chrome.tabs.query({
|
||||
url: CRX_BASE_URL + '*:*',
|
||||
}, function(tabsFromLastSession) {
|
||||
for (var i = 0; i < tabsFromLastSession.length; ++i) {
|
||||
chrome.tabs.reload(tabsFromLastSession[i].id);
|
||||
chrome.tabs.query(
|
||||
{
|
||||
url: CRX_BASE_URL + "*:*",
|
||||
},
|
||||
function(tabsFromLastSession) {
|
||||
for (var i = 0; i < tabsFromLastSession.length; ++i) {
|
||||
chrome.tabs.reload(tabsFromLastSession[i].id);
|
||||
}
|
||||
}
|
||||
});
|
||||
console.log('Set up extension URL router.');
|
||||
);
|
||||
console.log("Set up extension URL router.");
|
||||
|
||||
Object.keys(localStorage).forEach(function(key) {
|
||||
// The localStorage item is set upon unload by chromecom.js.
|
||||
var parsedKey = /^unload-(\d+)-(true|false)-(.+)/.exec(key);
|
||||
if (parsedKey) {
|
||||
var timeStart = parseInt(parsedKey[1], 10);
|
||||
var isHidden = parsedKey[2] === 'true';
|
||||
var isHidden = parsedKey[2] === "true";
|
||||
var url = parsedKey[3];
|
||||
if (Date.now() - timeStart < 3000) {
|
||||
// Is it a new item (younger than 3 seconds)? Assume that the extension
|
||||
// just reloaded, so restore the tab (work-around for crbug.com/511670).
|
||||
chrome.tabs.create({
|
||||
url: chrome.runtime.getURL('restoretab.html') +
|
||||
'?' + encodeURIComponent(url) +
|
||||
'#' + encodeURIComponent(localStorage.getItem(key)),
|
||||
url:
|
||||
chrome.runtime.getURL("restoretab.html") +
|
||||
"?" +
|
||||
encodeURIComponent(url) +
|
||||
"#" +
|
||||
encodeURIComponent(localStorage.getItem(key)),
|
||||
active: !isHidden,
|
||||
});
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ limitations under the License.
|
||||
/* eslint strict: ["error", "function"] */
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
"use strict";
|
||||
var storageLocal = chrome.storage.local;
|
||||
var storageSync = chrome.storage.sync;
|
||||
|
||||
@ -40,12 +40,12 @@ limitations under the License.
|
||||
function getStorageNames(callback) {
|
||||
var x = new XMLHttpRequest();
|
||||
var schema_location = chrome.runtime.getManifest().storage.managed_schema;
|
||||
x.open('get', chrome.runtime.getURL(schema_location));
|
||||
x.open("get", chrome.runtime.getURL(schema_location));
|
||||
x.onload = function() {
|
||||
var storageKeys = Object.keys(x.response.properties);
|
||||
callback(storageKeys);
|
||||
};
|
||||
x.responseType = 'json';
|
||||
x.responseType = "json";
|
||||
x.send();
|
||||
}
|
||||
|
||||
@ -54,8 +54,10 @@ limitations under the License.
|
||||
function migrateToSyncStorage(values) {
|
||||
storageSync.set(values, function() {
|
||||
if (chrome.runtime.lastError) {
|
||||
console.error('Failed to migrate settings due to an error: ' +
|
||||
chrome.runtime.lastError.message);
|
||||
console.error(
|
||||
"Failed to migrate settings due to an error: " +
|
||||
chrome.runtime.lastError.message
|
||||
);
|
||||
return;
|
||||
}
|
||||
// Migration successful. Delete local settings.
|
||||
@ -64,7 +66,8 @@ limitations under the License.
|
||||
// backend is corrupt), but since storageSync.set succeeded, consider
|
||||
// the migration successful.
|
||||
console.log(
|
||||
'Successfully migrated preferences from local to sync storage.');
|
||||
"Successfully migrated preferences from local to sync storage."
|
||||
);
|
||||
migrateRenamedStorage();
|
||||
});
|
||||
});
|
||||
@ -75,61 +78,82 @@ limitations under the License.
|
||||
// Note: We cannot modify managed preferences, so the migration logic is
|
||||
// duplicated in web/chromecom.js too.
|
||||
function migrateRenamedStorage() {
|
||||
storageSync.get([
|
||||
'enableHandToolOnLoad',
|
||||
'cursorToolOnLoad',
|
||||
'disableTextLayer',
|
||||
'enhanceTextSelection',
|
||||
'textLayerMode',
|
||||
'showPreviousViewOnLoad',
|
||||
'disablePageMode',
|
||||
'viewOnLoad',
|
||||
], function(items) {
|
||||
// Migration code for https://github.com/mozilla/pdf.js/pull/7635.
|
||||
if (typeof items.enableHandToolOnLoad === 'boolean') {
|
||||
if (items.enableHandToolOnLoad) {
|
||||
storageSync.set({
|
||||
cursorToolOnLoad: 1,
|
||||
}, function() {
|
||||
if (!chrome.runtime.lastError) {
|
||||
storageSync.remove('enableHandToolOnLoad');
|
||||
}
|
||||
});
|
||||
} else {
|
||||
storageSync.remove('enableHandToolOnLoad');
|
||||
storageSync.get(
|
||||
[
|
||||
"enableHandToolOnLoad",
|
||||
"cursorToolOnLoad",
|
||||
"disableTextLayer",
|
||||
"enhanceTextSelection",
|
||||
"textLayerMode",
|
||||
"showPreviousViewOnLoad",
|
||||
"disablePageMode",
|
||||
"viewOnLoad",
|
||||
],
|
||||
function(items) {
|
||||
// Migration code for https://github.com/mozilla/pdf.js/pull/7635.
|
||||
if (typeof items.enableHandToolOnLoad === "boolean") {
|
||||
if (items.enableHandToolOnLoad) {
|
||||
storageSync.set(
|
||||
{
|
||||
cursorToolOnLoad: 1,
|
||||
},
|
||||
function() {
|
||||
if (!chrome.runtime.lastError) {
|
||||
storageSync.remove("enableHandToolOnLoad");
|
||||
}
|
||||
}
|
||||
);
|
||||
} else {
|
||||
storageSync.remove("enableHandToolOnLoad");
|
||||
}
|
||||
}
|
||||
// Migration code for https://github.com/mozilla/pdf.js/pull/9479.
|
||||
if (typeof items.disableTextLayer === "boolean") {
|
||||
var textLayerMode = items.disableTextLayer
|
||||
? 0
|
||||
: items.enhanceTextSelection
|
||||
? 2
|
||||
: 1;
|
||||
if (textLayerMode !== 1) {
|
||||
// Overwrite if computed textLayerMode is not the default value (1).
|
||||
storageSync.set(
|
||||
{
|
||||
textLayerMode: textLayerMode,
|
||||
},
|
||||
function() {
|
||||
if (!chrome.runtime.lastError) {
|
||||
storageSync.remove([
|
||||
"disableTextLayer",
|
||||
"enhanceTextSelection",
|
||||
]);
|
||||
}
|
||||
}
|
||||
);
|
||||
} else {
|
||||
storageSync.remove(["disableTextLayer", "enhanceTextSelection"]);
|
||||
}
|
||||
}
|
||||
// Migration code for https://github.com/mozilla/pdf.js/pull/10502.
|
||||
if (typeof items.showPreviousViewOnLoad === "boolean") {
|
||||
if (!items.showPreviousViewOnLoad) {
|
||||
storageSync.set(
|
||||
{
|
||||
viewOnLoad: 1,
|
||||
},
|
||||
function() {
|
||||
if (!chrome.runtime.lastError) {
|
||||
storageSync.remove([
|
||||
"showPreviousViewOnLoad",
|
||||
"disablePageMode",
|
||||
]);
|
||||
}
|
||||
}
|
||||
);
|
||||
} else {
|
||||
storageSync.remove(["showPreviousViewOnLoad", "disablePageMode"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Migration code for https://github.com/mozilla/pdf.js/pull/9479.
|
||||
if (typeof items.disableTextLayer === 'boolean') {
|
||||
var textLayerMode = items.disableTextLayer ? 0 :
|
||||
items.enhanceTextSelection ? 2 : 1;
|
||||
if (textLayerMode !== 1) {
|
||||
// Overwrite if computed textLayerMode is not the default value (1).
|
||||
storageSync.set({
|
||||
textLayerMode: textLayerMode,
|
||||
}, function() {
|
||||
if (!chrome.runtime.lastError) {
|
||||
storageSync.remove(['disableTextLayer', 'enhanceTextSelection']);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
storageSync.remove(['disableTextLayer', 'enhanceTextSelection']);
|
||||
}
|
||||
}
|
||||
// Migration code for https://github.com/mozilla/pdf.js/pull/10502.
|
||||
if (typeof items.showPreviousViewOnLoad === 'boolean') {
|
||||
if (!items.showPreviousViewOnLoad) {
|
||||
storageSync.set({
|
||||
viewOnLoad: 1,
|
||||
}, function() {
|
||||
if (!chrome.runtime.lastError) {
|
||||
storageSync.remove(['showPreviousViewOnLoad', 'disablePageMode']);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
storageSync.remove(['showPreviousViewOnLoad', 'disablePageMode']);
|
||||
}
|
||||
}
|
||||
});
|
||||
);
|
||||
}
|
||||
})();
|
||||
|
@ -14,8 +14,8 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
var storageAreaName = chrome.storage.sync ? 'sync' : 'local';
|
||||
"use strict";
|
||||
var storageAreaName = chrome.storage.sync ? "sync" : "local";
|
||||
var storageArea = chrome.storage[storageAreaName];
|
||||
|
||||
Promise.all([
|
||||
@ -39,95 +39,103 @@ Promise.all([
|
||||
// Get the storage schema - a dictionary of preferences.
|
||||
var x = new XMLHttpRequest();
|
||||
var schema_location = chrome.runtime.getManifest().storage.managed_schema;
|
||||
x.open('get', chrome.runtime.getURL(schema_location));
|
||||
x.open("get", chrome.runtime.getURL(schema_location));
|
||||
x.onload = function() {
|
||||
resolve(x.response.properties);
|
||||
};
|
||||
x.responseType = 'json';
|
||||
x.responseType = "json";
|
||||
x.send();
|
||||
})
|
||||
]).then(function(values) {
|
||||
var managedPrefs = values[0];
|
||||
var userPrefs = values[1];
|
||||
var schema = values[2];
|
||||
function getPrefValue(prefName) {
|
||||
if (prefName in userPrefs) {
|
||||
return userPrefs[prefName];
|
||||
} else if (prefName in managedPrefs) {
|
||||
return managedPrefs[prefName];
|
||||
}
|
||||
return schema[prefName].default;
|
||||
}
|
||||
var prefNames = Object.keys(schema);
|
||||
var renderPreferenceFunctions = {};
|
||||
// Render options
|
||||
prefNames.forEach(function(prefName) {
|
||||
var prefSchema = schema[prefName];
|
||||
if (!prefSchema.title) {
|
||||
// Don't show preferences if the title is missing.
|
||||
return;
|
||||
}),
|
||||
])
|
||||
.then(function(values) {
|
||||
var managedPrefs = values[0];
|
||||
var userPrefs = values[1];
|
||||
var schema = values[2];
|
||||
function getPrefValue(prefName) {
|
||||
if (prefName in userPrefs) {
|
||||
return userPrefs[prefName];
|
||||
} else if (prefName in managedPrefs) {
|
||||
return managedPrefs[prefName];
|
||||
}
|
||||
return schema[prefName].default;
|
||||
}
|
||||
var prefNames = Object.keys(schema);
|
||||
var renderPreferenceFunctions = {};
|
||||
// Render options
|
||||
prefNames.forEach(function(prefName) {
|
||||
var prefSchema = schema[prefName];
|
||||
if (!prefSchema.title) {
|
||||
// Don't show preferences if the title is missing.
|
||||
return;
|
||||
}
|
||||
|
||||
// A DOM element with a method renderPreference.
|
||||
var renderPreference;
|
||||
if (prefSchema.type === 'boolean') {
|
||||
// Most prefs are booleans, render them in a generic way.
|
||||
renderPreference = renderBooleanPref(prefSchema.title,
|
||||
prefSchema.description,
|
||||
prefName);
|
||||
} else if (prefSchema.type === 'integer' && prefSchema.enum) {
|
||||
// Most other prefs are integer-valued enumerations, render them in a
|
||||
// generic way too.
|
||||
// Unlike the renderBooleanPref branch, each preference handled by this
|
||||
// branch still needs its own template in options.html with
|
||||
// id="$prefName-template".
|
||||
renderPreference = renderEnumPref(prefSchema.title, prefName);
|
||||
} else if (prefName === 'defaultZoomValue') {
|
||||
renderPreference = renderDefaultZoomValue(prefSchema.title);
|
||||
} else {
|
||||
// Should NEVER be reached. Only happens if a new type of preference is
|
||||
// added to the storage manifest.
|
||||
console.error('Don\'t know how to handle ' + prefName + '!');
|
||||
return;
|
||||
}
|
||||
// A DOM element with a method renderPreference.
|
||||
var renderPreference;
|
||||
if (prefSchema.type === "boolean") {
|
||||
// Most prefs are booleans, render them in a generic way.
|
||||
renderPreference = renderBooleanPref(
|
||||
prefSchema.title,
|
||||
prefSchema.description,
|
||||
prefName
|
||||
);
|
||||
} else if (prefSchema.type === "integer" && prefSchema.enum) {
|
||||
// Most other prefs are integer-valued enumerations, render them in a
|
||||
// generic way too.
|
||||
// Unlike the renderBooleanPref branch, each preference handled by this
|
||||
// branch still needs its own template in options.html with
|
||||
// id="$prefName-template".
|
||||
renderPreference = renderEnumPref(prefSchema.title, prefName);
|
||||
} else if (prefName === "defaultZoomValue") {
|
||||
renderPreference = renderDefaultZoomValue(prefSchema.title);
|
||||
} else {
|
||||
// Should NEVER be reached. Only happens if a new type of preference is
|
||||
// added to the storage manifest.
|
||||
console.error("Don't know how to handle " + prefName + "!");
|
||||
return;
|
||||
}
|
||||
|
||||
renderPreference(getPrefValue(prefName));
|
||||
renderPreferenceFunctions[prefName] = renderPreference;
|
||||
});
|
||||
|
||||
// Names of preferences that are displayed in the UI.
|
||||
var renderedPrefNames = Object.keys(renderPreferenceFunctions);
|
||||
|
||||
// Reset button to restore default settings.
|
||||
document.getElementById('reset-button').onclick = function() {
|
||||
userPrefs = {};
|
||||
storageArea.remove(prefNames, function() {
|
||||
renderedPrefNames.forEach(function(prefName) {
|
||||
renderPreferenceFunctions[prefName](getPrefValue(prefName));
|
||||
});
|
||||
renderPreference(getPrefValue(prefName));
|
||||
renderPreferenceFunctions[prefName] = renderPreference;
|
||||
});
|
||||
};
|
||||
|
||||
// Automatically update the UI when the preferences were changed elsewhere.
|
||||
chrome.storage.onChanged.addListener(function(changes, areaName) {
|
||||
var prefs = areaName === storageAreaName ? userPrefs :
|
||||
areaName === 'managed' ? managedPrefs : null;
|
||||
if (prefs) {
|
||||
renderedPrefNames.forEach(function(prefName) {
|
||||
var prefChanges = changes[prefName];
|
||||
if (prefChanges) {
|
||||
if ('newValue' in prefChanges) {
|
||||
userPrefs[prefName] = prefChanges.newValue;
|
||||
} else {
|
||||
// Otherwise the pref was deleted
|
||||
delete userPrefs[prefName];
|
||||
}
|
||||
// Names of preferences that are displayed in the UI.
|
||||
var renderedPrefNames = Object.keys(renderPreferenceFunctions);
|
||||
|
||||
// Reset button to restore default settings.
|
||||
document.getElementById("reset-button").onclick = function() {
|
||||
userPrefs = {};
|
||||
storageArea.remove(prefNames, function() {
|
||||
renderedPrefNames.forEach(function(prefName) {
|
||||
renderPreferenceFunctions[prefName](getPrefValue(prefName));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}).then(null, console.error.bind(console));
|
||||
};
|
||||
|
||||
// Automatically update the UI when the preferences were changed elsewhere.
|
||||
chrome.storage.onChanged.addListener(function(changes, areaName) {
|
||||
var prefs =
|
||||
areaName === storageAreaName
|
||||
? userPrefs
|
||||
: areaName === "managed"
|
||||
? managedPrefs
|
||||
: null;
|
||||
if (prefs) {
|
||||
renderedPrefNames.forEach(function(prefName) {
|
||||
var prefChanges = changes[prefName];
|
||||
if (prefChanges) {
|
||||
if ("newValue" in prefChanges) {
|
||||
userPrefs[prefName] = prefChanges.newValue;
|
||||
} else {
|
||||
// Otherwise the pref was deleted
|
||||
delete userPrefs[prefName];
|
||||
}
|
||||
renderPreferenceFunctions[prefName](getPrefValue(prefName));
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
})
|
||||
.then(null, console.error.bind(console));
|
||||
|
||||
function importTemplate(id) {
|
||||
return document.importNode(document.getElementById(id).content, true);
|
||||
@ -137,7 +145,7 @@ function importTemplate(id) {
|
||||
// function which updates the UI with the preference.
|
||||
|
||||
function renderBooleanPref(shortDescription, description, prefName) {
|
||||
var wrapper = importTemplate('checkbox-template');
|
||||
var wrapper = importTemplate("checkbox-template");
|
||||
wrapper.title = description;
|
||||
|
||||
var checkbox = wrapper.querySelector('input[type="checkbox"]');
|
||||
@ -146,8 +154,8 @@ function renderBooleanPref(shortDescription, description, prefName) {
|
||||
pref[prefName] = this.checked;
|
||||
storageArea.set(pref);
|
||||
};
|
||||
wrapper.querySelector('span').textContent = shortDescription;
|
||||
document.getElementById('settings-boxes').appendChild(wrapper);
|
||||
wrapper.querySelector("span").textContent = shortDescription;
|
||||
document.getElementById("settings-boxes").appendChild(wrapper);
|
||||
|
||||
function renderPreference(value) {
|
||||
checkbox.checked = value;
|
||||
@ -156,15 +164,15 @@ function renderBooleanPref(shortDescription, description, prefName) {
|
||||
}
|
||||
|
||||
function renderEnumPref(shortDescription, prefName) {
|
||||
var wrapper = importTemplate(prefName + '-template');
|
||||
var select = wrapper.querySelector('select');
|
||||
var wrapper = importTemplate(prefName + "-template");
|
||||
var select = wrapper.querySelector("select");
|
||||
select.onchange = function() {
|
||||
var pref = {};
|
||||
pref[prefName] = parseInt(this.value);
|
||||
storageArea.set(pref);
|
||||
};
|
||||
wrapper.querySelector('span').textContent = shortDescription;
|
||||
document.getElementById('settings-boxes').appendChild(wrapper);
|
||||
wrapper.querySelector("span").textContent = shortDescription;
|
||||
document.getElementById("settings-boxes").appendChild(wrapper);
|
||||
|
||||
function renderPreference(value) {
|
||||
select.value = value;
|
||||
@ -173,24 +181,24 @@ function renderEnumPref(shortDescription, prefName) {
|
||||
}
|
||||
|
||||
function renderDefaultZoomValue(shortDescription) {
|
||||
var wrapper = importTemplate('defaultZoomValue-template');
|
||||
var select = wrapper.querySelector('select');
|
||||
var wrapper = importTemplate("defaultZoomValue-template");
|
||||
var select = wrapper.querySelector("select");
|
||||
select.onchange = function() {
|
||||
storageArea.set({
|
||||
defaultZoomValue: this.value,
|
||||
});
|
||||
};
|
||||
wrapper.querySelector('span').textContent = shortDescription;
|
||||
document.getElementById('settings-boxes').appendChild(wrapper);
|
||||
wrapper.querySelector("span").textContent = shortDescription;
|
||||
document.getElementById("settings-boxes").appendChild(wrapper);
|
||||
|
||||
function renderPreference(value) {
|
||||
value = value || 'auto';
|
||||
value = value || "auto";
|
||||
select.value = value;
|
||||
var customOption = select.querySelector('option.custom-zoom');
|
||||
var customOption = select.querySelector("option.custom-zoom");
|
||||
if (select.selectedIndex === -1 && value) {
|
||||
// Custom zoom percentage, e.g. set via managed preferences.
|
||||
// [zoom] or [zoom],[left],[top]
|
||||
customOption.text = value.indexOf(',') > 0 ? value : value + '%';
|
||||
customOption.text = value.indexOf(",") > 0 ? value : value + "%";
|
||||
customOption.value = value;
|
||||
customOption.hidden = false;
|
||||
customOption.selected = true;
|
||||
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
"use strict";
|
||||
|
||||
(function PageActionClosure() {
|
||||
/**
|
||||
@ -29,16 +29,16 @@ limitations under the License.
|
||||
url = url[1];
|
||||
chrome.pageAction.setPopup({
|
||||
tabId: tabId,
|
||||
popup: '/pageAction/popup.html?file=' + encodeURIComponent(url),
|
||||
popup: "/pageAction/popup.html?file=" + encodeURIComponent(url),
|
||||
});
|
||||
chrome.pageAction.show(tabId);
|
||||
} else {
|
||||
console.log('Unable to get PDF url from ' + displayUrl);
|
||||
console.log("Unable to get PDF url from " + displayUrl);
|
||||
}
|
||||
}
|
||||
|
||||
chrome.runtime.onMessage.addListener(function(message, sender) {
|
||||
if (message === 'showPageAction' && sender.tab) {
|
||||
if (message === "showPageAction" && sender.tab) {
|
||||
showPageAction(sender.tab.id, sender.tab.url);
|
||||
}
|
||||
});
|
||||
|
@ -13,7 +13,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
"use strict";
|
||||
|
||||
var url = location.search.match(/[&?]file=([^&]+)/i);
|
||||
if (url) {
|
||||
|
@ -17,7 +17,7 @@ limitations under the License.
|
||||
/* import-globals-from pdfHandler.js */
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
"use strict";
|
||||
|
||||
if (!chrome.fileBrowserHandler) {
|
||||
// Not on Chromium OS, bail out
|
||||
@ -33,7 +33,7 @@ limitations under the License.
|
||||
* @param {Object} details Object of type FileHandlerExecuteEventDetails
|
||||
*/
|
||||
function onExecuteFileBrowserHandler(id, details) {
|
||||
if (id !== 'open-as-pdf') {
|
||||
if (id !== "open-as-pdf") {
|
||||
return;
|
||||
}
|
||||
var fileEntries = details.entries;
|
||||
@ -49,7 +49,7 @@ limitations under the License.
|
||||
chrome.windows.getLastFocused(function(chromeWindow) {
|
||||
var windowId = chromeWindow && chromeWindow.id;
|
||||
if (windowId) {
|
||||
chrome.windows.update(windowId, { focused: true, });
|
||||
chrome.windows.update(windowId, { focused: true });
|
||||
}
|
||||
openViewer(windowId, fileEntries);
|
||||
});
|
||||
@ -69,26 +69,34 @@ limitations under the License.
|
||||
var fileEntry = fileEntries.shift();
|
||||
var url = fileEntry.toURL();
|
||||
// Use drive: alias to get shorter (more human-readable) URLs.
|
||||
url = url.replace(/^filesystem:chrome-extension:\/\/[a-p]{32}\/external\//,
|
||||
'drive:');
|
||||
url = url.replace(
|
||||
/^filesystem:chrome-extension:\/\/[a-p]{32}\/external\//,
|
||||
"drive:"
|
||||
);
|
||||
url = getViewerURL(url);
|
||||
|
||||
if (windowId) {
|
||||
chrome.tabs.create({
|
||||
windowId: windowId,
|
||||
active: true,
|
||||
url: url,
|
||||
}, function() {
|
||||
openViewer(windowId, fileEntries);
|
||||
});
|
||||
chrome.tabs.create(
|
||||
{
|
||||
windowId: windowId,
|
||||
active: true,
|
||||
url: url,
|
||||
},
|
||||
function() {
|
||||
openViewer(windowId, fileEntries);
|
||||
}
|
||||
);
|
||||
} else {
|
||||
chrome.windows.create({
|
||||
type: 'normal',
|
||||
focused: true,
|
||||
url: url,
|
||||
}, function(chromeWindow) {
|
||||
openViewer(chromeWindow.id, fileEntries);
|
||||
});
|
||||
chrome.windows.create(
|
||||
{
|
||||
type: "normal",
|
||||
focused: true,
|
||||
url: url,
|
||||
},
|
||||
function(chromeWindow) {
|
||||
openViewer(chromeWindow.id, fileEntries);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
@ -15,12 +15,12 @@ limitations under the License.
|
||||
*/
|
||||
/* import-globals-from preserve-referer.js */
|
||||
|
||||
'use strict';
|
||||
"use strict";
|
||||
|
||||
var VIEWER_URL = chrome.extension.getURL('content/web/viewer.html');
|
||||
var VIEWER_URL = chrome.extension.getURL("content/web/viewer.html");
|
||||
|
||||
function getViewerURL(pdf_url) {
|
||||
return VIEWER_URL + '?file=' + encodeURIComponent(pdf_url);
|
||||
return VIEWER_URL + "?file=" + encodeURIComponent(pdf_url);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -29,7 +29,7 @@ function getViewerURL(pdf_url) {
|
||||
* @returns {boolean} True if the PDF file should be downloaded.
|
||||
*/
|
||||
function isPdfDownloadable(details) {
|
||||
if (details.url.includes('pdfjs.action=download')) {
|
||||
if (details.url.includes("pdfjs.action=download")) {
|
||||
return true;
|
||||
}
|
||||
// Display the PDF viewer regardless of the Content-Disposition header if the
|
||||
@ -39,12 +39,13 @@ function isPdfDownloadable(details) {
|
||||
// viewer to open the PDF, but first check whether the Content-Disposition
|
||||
// header specifies an attachment. This allows sites like Google Drive to
|
||||
// operate correctly (#6106).
|
||||
if (details.type === 'main_frame' && !details.url.includes('=download')) {
|
||||
if (details.type === "main_frame" && !details.url.includes("=download")) {
|
||||
return false;
|
||||
}
|
||||
var cdHeader = (details.responseHeaders &&
|
||||
getHeaderFromHeaders(details.responseHeaders, 'content-disposition'));
|
||||
return (cdHeader && /^attachment/i.test(cdHeader.value));
|
||||
var cdHeader =
|
||||
details.responseHeaders &&
|
||||
getHeaderFromHeaders(details.responseHeaders, "content-disposition");
|
||||
return cdHeader && /^attachment/i.test(cdHeader.value);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -70,18 +71,23 @@ function getHeaderFromHeaders(headers, headerName) {
|
||||
* @returns {boolean} True if the resource is a PDF file.
|
||||
*/
|
||||
function isPdfFile(details) {
|
||||
var header = getHeaderFromHeaders(details.responseHeaders, 'content-type');
|
||||
var header = getHeaderFromHeaders(details.responseHeaders, "content-type");
|
||||
if (header) {
|
||||
var headerValue = header.value.toLowerCase().split(';', 1)[0].trim();
|
||||
if (headerValue === 'application/pdf') {
|
||||
var headerValue = header.value
|
||||
.toLowerCase()
|
||||
.split(";", 1)[0]
|
||||
.trim();
|
||||
if (headerValue === "application/pdf") {
|
||||
return true;
|
||||
}
|
||||
if (headerValue === 'application/octet-stream') {
|
||||
if (details.url.toLowerCase().indexOf('.pdf') > 0) {
|
||||
if (headerValue === "application/octet-stream") {
|
||||
if (details.url.toLowerCase().indexOf(".pdf") > 0) {
|
||||
return true;
|
||||
}
|
||||
var cdHeader =
|
||||
getHeaderFromHeaders(details.responseHeaders, 'content-disposition');
|
||||
var cdHeader = getHeaderFromHeaders(
|
||||
details.responseHeaders,
|
||||
"content-disposition"
|
||||
);
|
||||
if (cdHeader && /\.pdf(["']|$)/i.test(cdHeader.value)) {
|
||||
return true;
|
||||
}
|
||||
@ -101,21 +107,21 @@ function isPdfFile(details) {
|
||||
*/
|
||||
function getHeadersWithContentDispositionAttachment(details) {
|
||||
var headers = details.responseHeaders;
|
||||
var cdHeader = getHeaderFromHeaders(headers, 'content-disposition');
|
||||
var cdHeader = getHeaderFromHeaders(headers, "content-disposition");
|
||||
if (!cdHeader) {
|
||||
cdHeader = { name: 'Content-Disposition', };
|
||||
cdHeader = { name: "Content-Disposition" };
|
||||
headers.push(cdHeader);
|
||||
}
|
||||
if (!/^attachment/i.test(cdHeader.value)) {
|
||||
cdHeader.value = 'attachment' + cdHeader.value.replace(/^[^;]+/i, '');
|
||||
return { responseHeaders: headers, };
|
||||
cdHeader.value = "attachment" + cdHeader.value.replace(/^[^;]+/i, "");
|
||||
return { responseHeaders: headers };
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
chrome.webRequest.onHeadersReceived.addListener(
|
||||
function(details) {
|
||||
if (details.method !== 'GET') {
|
||||
if (details.method !== "GET") {
|
||||
// Don't intercept POST requests until http://crbug.com/104058 is fixed.
|
||||
return undefined;
|
||||
}
|
||||
@ -132,15 +138,14 @@ chrome.webRequest.onHeadersReceived.addListener(
|
||||
// Implemented in preserve-referer.js
|
||||
saveReferer(details);
|
||||
|
||||
return { redirectUrl: viewerUrl, };
|
||||
return { redirectUrl: viewerUrl };
|
||||
},
|
||||
{
|
||||
urls: [
|
||||
'<all_urls>'
|
||||
],
|
||||
types: ['main_frame', 'sub_frame'],
|
||||
urls: ["<all_urls>"],
|
||||
types: ["main_frame", "sub_frame"],
|
||||
},
|
||||
['blocking', 'responseHeaders']);
|
||||
["blocking", "responseHeaders"]
|
||||
);
|
||||
|
||||
chrome.webRequest.onBeforeRequest.addListener(
|
||||
function(details) {
|
||||
@ -150,26 +155,26 @@ chrome.webRequest.onBeforeRequest.addListener(
|
||||
|
||||
var viewerUrl = getViewerURL(details.url);
|
||||
|
||||
return { redirectUrl: viewerUrl, };
|
||||
return { redirectUrl: viewerUrl };
|
||||
},
|
||||
{
|
||||
urls: [
|
||||
'file://*/*.pdf',
|
||||
'file://*/*.PDF',
|
||||
...(
|
||||
// Duck-typing: MediaError.prototype.message was added in Chrome 59.
|
||||
MediaError.prototype.hasOwnProperty('message') ? [] :
|
||||
[
|
||||
// Note: Chrome 59 has disabled ftp resource loading by default:
|
||||
// https://www.chromestatus.com/feature/5709390967472128
|
||||
'ftp://*/*.pdf',
|
||||
'ftp://*/*.PDF',
|
||||
]
|
||||
),
|
||||
"file://*/*.pdf",
|
||||
"file://*/*.PDF",
|
||||
...// Duck-typing: MediaError.prototype.message was added in Chrome 59.
|
||||
(MediaError.prototype.hasOwnProperty("message")
|
||||
? []
|
||||
: [
|
||||
// Note: Chrome 59 has disabled ftp resource loading by default:
|
||||
// https://www.chromestatus.com/feature/5709390967472128
|
||||
"ftp://*/*.pdf",
|
||||
"ftp://*/*.PDF",
|
||||
]),
|
||||
],
|
||||
types: ['main_frame', 'sub_frame'],
|
||||
types: ["main_frame", "sub_frame"],
|
||||
},
|
||||
['blocking']);
|
||||
["blocking"]
|
||||
);
|
||||
|
||||
chrome.extension.isAllowedFileSchemeAccess(function(isAllowedAccess) {
|
||||
if (isAllowedAccess) {
|
||||
@ -180,29 +185,35 @@ chrome.extension.isAllowedFileSchemeAccess(function(isAllowedAccess) {
|
||||
// API though, and we can replace the tab with the viewer.
|
||||
// The viewer will detect that it has no access to file:-URLs, and prompt the
|
||||
// user to activate file permissions.
|
||||
chrome.webNavigation.onBeforeNavigate.addListener(function(details) {
|
||||
if (details.frameId === 0 && !isPdfDownloadable(details)) {
|
||||
chrome.tabs.update(details.tabId, {
|
||||
url: getViewerURL(details.url),
|
||||
});
|
||||
chrome.webNavigation.onBeforeNavigate.addListener(
|
||||
function(details) {
|
||||
if (details.frameId === 0 && !isPdfDownloadable(details)) {
|
||||
chrome.tabs.update(details.tabId, {
|
||||
url: getViewerURL(details.url),
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
url: [
|
||||
{
|
||||
urlPrefix: "file://",
|
||||
pathSuffix: ".pdf",
|
||||
},
|
||||
{
|
||||
urlPrefix: "file://",
|
||||
pathSuffix: ".PDF",
|
||||
},
|
||||
],
|
||||
}
|
||||
}, {
|
||||
url: [{
|
||||
urlPrefix: 'file://',
|
||||
pathSuffix: '.pdf',
|
||||
}, {
|
||||
urlPrefix: 'file://',
|
||||
pathSuffix: '.PDF',
|
||||
}],
|
||||
});
|
||||
);
|
||||
});
|
||||
|
||||
chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
|
||||
if (message && message.action === 'getParentOrigin') {
|
||||
if (message && message.action === "getParentOrigin") {
|
||||
// getParentOrigin is used to determine whether it is safe to embed a
|
||||
// sensitive (local) file in a frame.
|
||||
if (!sender.tab) {
|
||||
sendResponse('');
|
||||
sendResponse("");
|
||||
return undefined;
|
||||
}
|
||||
// TODO: This should be the URL of the parent frame, not the tab. But
|
||||
@ -211,11 +222,11 @@ chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
|
||||
// for making security decisions.
|
||||
var parentUrl = sender.tab.url;
|
||||
if (!parentUrl) {
|
||||
sendResponse('');
|
||||
sendResponse("");
|
||||
return undefined;
|
||||
}
|
||||
if (parentUrl.lastIndexOf('file:', 0) === 0) {
|
||||
sendResponse('file://');
|
||||
if (parentUrl.lastIndexOf("file:", 0) === 0) {
|
||||
sendResponse("file://");
|
||||
return undefined;
|
||||
}
|
||||
// The regexp should always match for valid URLs, but in case it doesn't,
|
||||
@ -224,12 +235,12 @@ chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
|
||||
sendResponse(origin ? origin[1] : parentUrl);
|
||||
return true;
|
||||
}
|
||||
if (message && message.action === 'isAllowedFileSchemeAccess') {
|
||||
if (message && message.action === "isAllowedFileSchemeAccess") {
|
||||
chrome.extension.isAllowedFileSchemeAccess(sendResponse);
|
||||
return true;
|
||||
}
|
||||
if (message && message.action === 'openExtensionsPageForFileAccess') {
|
||||
var url = 'chrome://extensions/?id=' + chrome.runtime.id;
|
||||
if (message && message.action === "openExtensionsPageForFileAccess") {
|
||||
var url = "chrome://extensions/?id=" + chrome.runtime.id;
|
||||
if (message.data.newTab) {
|
||||
chrome.tabs.create({
|
||||
windowId: sender.tab.windowId,
|
||||
@ -248,7 +259,7 @@ chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
|
||||
|
||||
// Remove keys from storage that were once part of the deleted feature-detect.js
|
||||
chrome.storage.local.remove([
|
||||
'featureDetectLastUA',
|
||||
'webRequestRedirectUrl',
|
||||
'extensionSupportsFTP',
|
||||
"featureDetectLastUA",
|
||||
"webRequestRedirectUrl",
|
||||
"extensionSupportsFTP",
|
||||
]);
|
||||
|
@ -15,7 +15,7 @@ limitations under the License.
|
||||
*/
|
||||
/* import-globals-from pdfHandler.js */
|
||||
|
||||
'use strict';
|
||||
"use strict";
|
||||
/**
|
||||
* This file is one part of the Referer persistency implementation. The other
|
||||
* part resides in chromecom.js.
|
||||
@ -45,21 +45,25 @@ var extraInfoSpecWithHeaders; // = ['requestHeaders', 'extraHeaders']
|
||||
|
||||
(function() {
|
||||
var requestFilter = {
|
||||
urls: ['*://*/*'],
|
||||
types: ['main_frame', 'sub_frame'],
|
||||
urls: ["*://*/*"],
|
||||
types: ["main_frame", "sub_frame"],
|
||||
};
|
||||
function registerListener(extraInfoSpec) {
|
||||
extraInfoSpecWithHeaders = extraInfoSpec;
|
||||
// May throw if the given extraInfoSpec is unsupported.
|
||||
chrome.webRequest.onSendHeaders.addListener(function(details) {
|
||||
g_requestHeaders[details.requestId] = details.requestHeaders;
|
||||
}, requestFilter, extraInfoSpec);
|
||||
chrome.webRequest.onSendHeaders.addListener(
|
||||
function(details) {
|
||||
g_requestHeaders[details.requestId] = details.requestHeaders;
|
||||
},
|
||||
requestFilter,
|
||||
extraInfoSpec
|
||||
);
|
||||
}
|
||||
try {
|
||||
registerListener(['requestHeaders', 'extraHeaders']);
|
||||
registerListener(["requestHeaders", "extraHeaders"]);
|
||||
} catch (e) {
|
||||
// "extraHeaders" is not supported in Chrome 71 and earlier.
|
||||
registerListener(['requestHeaders']);
|
||||
registerListener(["requestHeaders"]);
|
||||
}
|
||||
chrome.webRequest.onBeforeRedirect.addListener(forgetHeaders, requestFilter);
|
||||
chrome.webRequest.onCompleted.addListener(forgetHeaders, requestFilter);
|
||||
@ -73,9 +77,10 @@ var extraInfoSpecWithHeaders; // = ['requestHeaders', 'extraHeaders']
|
||||
* @param {object} details - onHeadersReceived event data.
|
||||
*/
|
||||
function saveReferer(details) {
|
||||
var referer = g_requestHeaders[details.requestId] &&
|
||||
getHeaderFromHeaders(g_requestHeaders[details.requestId], 'referer');
|
||||
referer = referer && referer.value || '';
|
||||
var referer =
|
||||
g_requestHeaders[details.requestId] &&
|
||||
getHeaderFromHeaders(g_requestHeaders[details.requestId], "referer");
|
||||
referer = (referer && referer.value) || "";
|
||||
if (!g_referrers[details.tabId]) {
|
||||
g_referrers[details.tabId] = {};
|
||||
}
|
||||
@ -90,11 +95,11 @@ chrome.tabs.onRemoved.addListener(function(tabId) {
|
||||
// to matching PDF resource requests (only if the Referer is non-empty). The
|
||||
// handler is removed as soon as the PDF viewer frame is unloaded.
|
||||
chrome.runtime.onConnect.addListener(function onReceivePort(port) {
|
||||
if (port.name !== 'chromecom-referrer') {
|
||||
if (port.name !== "chromecom-referrer") {
|
||||
return;
|
||||
}
|
||||
// Note: sender.frameId is only set in Chrome 41+.
|
||||
if (!('frameId' in port.sender)) {
|
||||
if (!("frameId" in port.sender)) {
|
||||
port.disconnect();
|
||||
return;
|
||||
}
|
||||
@ -102,7 +107,7 @@ chrome.runtime.onConnect.addListener(function onReceivePort(port) {
|
||||
var frameId = port.sender.frameId;
|
||||
|
||||
// If the PDF is viewed for the first time, then the referer will be set here.
|
||||
var referer = g_referrers[tabId] && g_referrers[tabId][frameId] || '';
|
||||
var referer = (g_referrers[tabId] && g_referrers[tabId][frameId]) || "";
|
||||
port.onMessage.addListener(function(data) {
|
||||
// If the viewer was opened directly (without opening a PDF URL first), then
|
||||
// the background script does not know about g_referrers, but the viewer may
|
||||
@ -113,11 +118,15 @@ chrome.runtime.onConnect.addListener(function onReceivePort(port) {
|
||||
chrome.webRequest.onBeforeSendHeaders.removeListener(onBeforeSendHeaders);
|
||||
if (referer) {
|
||||
// Only add a blocking request handler if the referer has to be rewritten.
|
||||
chrome.webRequest.onBeforeSendHeaders.addListener(onBeforeSendHeaders, {
|
||||
urls: [data.requestUrl],
|
||||
types: ['xmlhttprequest'],
|
||||
tabId: tabId,
|
||||
}, ['blocking', ...extraInfoSpecWithHeaders]);
|
||||
chrome.webRequest.onBeforeSendHeaders.addListener(
|
||||
onBeforeSendHeaders,
|
||||
{
|
||||
urls: [data.requestUrl],
|
||||
types: ["xmlhttprequest"],
|
||||
tabId: tabId,
|
||||
},
|
||||
["blocking", ...extraInfoSpecWithHeaders]
|
||||
);
|
||||
}
|
||||
// Acknowledge the message, and include the latest referer for this frame.
|
||||
port.postMessage(referer);
|
||||
@ -134,29 +143,35 @@ chrome.runtime.onConnect.addListener(function onReceivePort(port) {
|
||||
|
||||
// Expose some response headers for fetch API calls from PDF.js;
|
||||
// This is a work-around for https://crbug.com/784528
|
||||
chrome.webRequest.onHeadersReceived.addListener(exposeOnHeadersReceived, {
|
||||
urls: ['https://*/*'],
|
||||
types: ['xmlhttprequest'],
|
||||
tabId: tabId,
|
||||
}, ['blocking', 'responseHeaders']);
|
||||
chrome.webRequest.onHeadersReceived.addListener(
|
||||
exposeOnHeadersReceived,
|
||||
{
|
||||
urls: ["https://*/*"],
|
||||
types: ["xmlhttprequest"],
|
||||
tabId: tabId,
|
||||
},
|
||||
["blocking", "responseHeaders"]
|
||||
);
|
||||
|
||||
function onBeforeSendHeaders(details) {
|
||||
if (details.frameId !== frameId) {
|
||||
return undefined;
|
||||
}
|
||||
var headers = details.requestHeaders;
|
||||
var refererHeader = getHeaderFromHeaders(headers, 'referer');
|
||||
var refererHeader = getHeaderFromHeaders(headers, "referer");
|
||||
if (!refererHeader) {
|
||||
refererHeader = { name: 'Referer', };
|
||||
refererHeader = { name: "Referer" };
|
||||
headers.push(refererHeader);
|
||||
} else if (refererHeader.value &&
|
||||
refererHeader.value.lastIndexOf('chrome-extension:', 0) !== 0) {
|
||||
} else if (
|
||||
refererHeader.value &&
|
||||
refererHeader.value.lastIndexOf("chrome-extension:", 0) !== 0
|
||||
) {
|
||||
// Sanity check. If the referer is set, and the value is not the URL of
|
||||
// this extension, then the request was not initiated by this extension.
|
||||
return undefined;
|
||||
}
|
||||
refererHeader.value = referer;
|
||||
return { requestHeaders: headers, };
|
||||
return { requestHeaders: headers };
|
||||
}
|
||||
|
||||
function exposeOnHeadersReceived(details) {
|
||||
@ -164,16 +179,16 @@ chrome.runtime.onConnect.addListener(function onReceivePort(port) {
|
||||
return undefined;
|
||||
}
|
||||
var headers = details.responseHeaders;
|
||||
var aceh = getHeaderFromHeaders(headers, 'access-control-expose-headers');
|
||||
var aceh = getHeaderFromHeaders(headers, "access-control-expose-headers");
|
||||
// List of headers that PDF.js uses in src/display/network_utils.js
|
||||
var acehValue =
|
||||
'accept-ranges,content-encoding,content-length,content-disposition';
|
||||
"accept-ranges,content-encoding,content-length,content-disposition";
|
||||
if (aceh) {
|
||||
aceh.value += ',' + acehValue;
|
||||
aceh.value += "," + acehValue;
|
||||
} else {
|
||||
aceh = { name: 'Access-Control-Expose-Headers', value: acehValue, };
|
||||
aceh = { name: "Access-Control-Expose-Headers", value: acehValue };
|
||||
headers.push(aceh);
|
||||
}
|
||||
return { responseHeaders: headers, };
|
||||
return { responseHeaders: headers };
|
||||
}
|
||||
});
|
||||
|
@ -20,12 +20,12 @@ limitations under the License.
|
||||
* - extension-router.js retrieves the saved state and opens restoretab.html
|
||||
* - restoretab.html (this script) restores the URL and history state.
|
||||
*/
|
||||
'use strict';
|
||||
"use strict";
|
||||
|
||||
var url = decodeURIComponent(location.search.slice(1));
|
||||
var historyState = decodeURIComponent(location.hash.slice(1));
|
||||
|
||||
historyState = historyState === 'undefined' ? null : JSON.parse(historyState);
|
||||
historyState = historyState === "undefined" ? null : JSON.parse(historyState);
|
||||
|
||||
history.replaceState(historyState, null, url);
|
||||
location.reload();
|
||||
|
@ -14,13 +14,13 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
"use strict";
|
||||
|
||||
// Do not reload the extension when an update becomes available, UNLESS the PDF
|
||||
// viewer is not displaying any PDF files. Otherwise the tabs would close, which
|
||||
// is quite disruptive (crbug.com/511670).
|
||||
chrome.runtime.onUpdateAvailable.addListener(function() {
|
||||
if (chrome.extension.getViews({ type: 'tab', }).length === 0) {
|
||||
chrome.runtime.reload();
|
||||
}
|
||||
if (chrome.extension.getViews({ type: "tab" }).length === 0) {
|
||||
chrome.runtime.reload();
|
||||
}
|
||||
});
|
||||
|
@ -16,19 +16,19 @@ limitations under the License.
|
||||
/* eslint strict: ["error", "function"] */
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
"use strict";
|
||||
// This module sends the browser and extension version to a server, to
|
||||
// determine whether it is safe to drop support for old Chrome versions in
|
||||
// future extension updates.
|
||||
//
|
||||
// The source code for the server is available at:
|
||||
// https://github.com/Rob--W/pdfjs-telemetry
|
||||
var LOG_URL = 'https://pdfjs.robwu.nl/logpdfjs';
|
||||
var LOG_URL = "https://pdfjs.robwu.nl/logpdfjs";
|
||||
|
||||
// The minimum time to wait before sending a ping, so that we don't send too
|
||||
// many requests even if the user restarts their browser very often.
|
||||
// We want one ping a day, so a minimum delay of 12 hours should be OK.
|
||||
var MINIMUM_TIME_BETWEEN_PING = 12 * 36E5;
|
||||
var MINIMUM_TIME_BETWEEN_PING = 12 * 36e5;
|
||||
|
||||
if (chrome.extension.inIncognitoContext) {
|
||||
// The extension uses incognito split mode, so there are two background
|
||||
@ -36,14 +36,14 @@ limitations under the License.
|
||||
return;
|
||||
}
|
||||
|
||||
if (chrome.runtime.id !== 'oemmndcbldboiebfnladdacbdfmadadm') {
|
||||
if (chrome.runtime.id !== "oemmndcbldboiebfnladdacbdfmadadm") {
|
||||
// Only send telemetry for the official PDF.js extension.
|
||||
console.warn('Disabled telemetry because this is not an official build.');
|
||||
console.warn("Disabled telemetry because this is not an official build.");
|
||||
return;
|
||||
}
|
||||
|
||||
maybeSendPing();
|
||||
setInterval(maybeSendPing, 36E5);
|
||||
setInterval(maybeSendPing, 36e5);
|
||||
|
||||
function maybeSendPing() {
|
||||
getLoggingPref(function(didOptOut) {
|
||||
@ -70,28 +70,28 @@ limitations under the License.
|
||||
|
||||
var deduplication_id = getDeduplicationId(wasUpdated);
|
||||
var extension_version = chrome.runtime.getManifest().version;
|
||||
if (window.Request && 'mode' in Request.prototype) {
|
||||
if (window.Request && "mode" in Request.prototype) {
|
||||
// fetch is supported in extensions since Chrome 42 (though the above
|
||||
// feature-detection method detects Chrome 43+).
|
||||
// Unlike XMLHttpRequest, fetch omits credentials such as cookies in the
|
||||
// requests, which guarantees that the server cannot track the client
|
||||
// via HTTP cookies.
|
||||
fetch(LOG_URL, {
|
||||
method: 'POST',
|
||||
method: "POST",
|
||||
headers: new Headers({
|
||||
'Deduplication-Id': deduplication_id,
|
||||
'Extension-Version': extension_version,
|
||||
"Deduplication-Id": deduplication_id,
|
||||
"Extension-Version": extension_version,
|
||||
}),
|
||||
// Set mode=cors so that the above custom headers are included in the
|
||||
// request.
|
||||
mode: 'cors',
|
||||
mode: "cors",
|
||||
});
|
||||
return;
|
||||
}
|
||||
var x = new XMLHttpRequest();
|
||||
x.open('POST', LOG_URL);
|
||||
x.setRequestHeader('Deduplication-Id', deduplication_id);
|
||||
x.setRequestHeader('Extension-Version', extension_version);
|
||||
x.open("POST", LOG_URL);
|
||||
x.setRequestHeader("Deduplication-Id", deduplication_id);
|
||||
x.setRequestHeader("Extension-Version", extension_version);
|
||||
x.send();
|
||||
});
|
||||
}
|
||||
@ -107,12 +107,12 @@ limitations under the License.
|
||||
// so it is OK to change the ID if the browser is updated. By changing the
|
||||
// ID, the server cannot track users for a long period even if it wants to.
|
||||
if (!id || !/^[0-9a-f]{10}$/.test(id) || wasUpdated) {
|
||||
id = '';
|
||||
id = "";
|
||||
var buf = new Uint8Array(5);
|
||||
crypto.getRandomValues(buf);
|
||||
for (var i = 0; i < buf.length; ++i) {
|
||||
var c = buf[i];
|
||||
id += (c >>> 4).toString(16) + (c & 0xF).toString(16);
|
||||
id += (c >>> 4).toString(16) + (c & 0xf).toString(16);
|
||||
}
|
||||
localStorage.telemetryDeduplicationId = id;
|
||||
}
|
||||
@ -139,12 +139,12 @@ limitations under the License.
|
||||
*/
|
||||
function getLoggingPref(callback) {
|
||||
// Try to look up the preference in the storage, in the following order:
|
||||
var areas = ['sync', 'local', 'managed'];
|
||||
var areas = ["sync", "local", "managed"];
|
||||
|
||||
next();
|
||||
function next(result) {
|
||||
var storageAreaName = areas.shift();
|
||||
if (typeof result === 'boolean' || !storageAreaName) {
|
||||
if (typeof result === "boolean" || !storageAreaName) {
|
||||
callback(result);
|
||||
return;
|
||||
}
|
||||
@ -154,7 +154,7 @@ limitations under the License.
|
||||
return;
|
||||
}
|
||||
|
||||
chrome.storage[storageAreaName].get('disableTelemetry', function(items) {
|
||||
chrome.storage[storageAreaName].get("disableTelemetry", function(items) {
|
||||
next(items && items.disableTelemetry);
|
||||
});
|
||||
}
|
||||
|
@ -126,6 +126,6 @@
|
||||
},
|
||||
|
||||
// translate an element or document fragment
|
||||
translate: translateFragment
|
||||
translate: translateFragment,
|
||||
};
|
||||
})(this);
|
||||
|
153
external/builder/builder.js
vendored
153
external/builder/builder.js
vendored
@ -1,8 +1,8 @@
|
||||
'use strict';
|
||||
"use strict";
|
||||
|
||||
var fs = require('fs'),
|
||||
path = require('path'),
|
||||
vm = require('vm');
|
||||
var fs = require("fs"),
|
||||
path = require("path"),
|
||||
vm = require("vm");
|
||||
|
||||
/**
|
||||
* A simple preprocessor that is based on the Firefox preprocessor
|
||||
@ -34,9 +34,12 @@ var fs = require('fs'),
|
||||
*/
|
||||
function preprocess(inFilename, outFilename, defines) {
|
||||
// TODO make this really read line by line.
|
||||
var lines = fs.readFileSync(inFilename).toString().split('\n');
|
||||
var lines = fs
|
||||
.readFileSync(inFilename)
|
||||
.toString()
|
||||
.split("\n");
|
||||
var totalLines = lines.length;
|
||||
var out = '';
|
||||
var out = "";
|
||||
var i = 0;
|
||||
function readLine() {
|
||||
if (i < totalLines) {
|
||||
@ -44,19 +47,29 @@ function preprocess(inFilename, outFilename, defines) {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
var writeLine = (typeof outFilename === 'function' ? outFilename :
|
||||
function(line) {
|
||||
out += line + '\n';
|
||||
});
|
||||
var writeLine =
|
||||
typeof outFilename === "function"
|
||||
? outFilename
|
||||
: function(line) {
|
||||
out += line + "\n";
|
||||
};
|
||||
function evaluateCondition(code) {
|
||||
if (!code || !code.trim()) {
|
||||
throw new Error('No JavaScript expression given at ' + loc());
|
||||
throw new Error("No JavaScript expression given at " + loc());
|
||||
}
|
||||
try {
|
||||
return vm.runInNewContext(code, defines, { displayErrors: false, });
|
||||
return vm.runInNewContext(code, defines, { displayErrors: false });
|
||||
} catch (e) {
|
||||
throw new Error('Could not evaluate "' + code + '" at ' + loc() + '\n' +
|
||||
e.name + ': ' + e.message);
|
||||
throw new Error(
|
||||
'Could not evaluate "' +
|
||||
code +
|
||||
'" at ' +
|
||||
loc() +
|
||||
"\n" +
|
||||
e.name +
|
||||
": " +
|
||||
e.message
|
||||
);
|
||||
}
|
||||
}
|
||||
function include(file) {
|
||||
@ -64,15 +77,18 @@ function preprocess(inFilename, outFilename, defines) {
|
||||
var dir = path.dirname(realPath);
|
||||
try {
|
||||
var fullpath;
|
||||
if (file.indexOf('$ROOT/') === 0) {
|
||||
fullpath = path.join(__dirname, '../..',
|
||||
file.substring('$ROOT/'.length));
|
||||
if (file.indexOf("$ROOT/") === 0) {
|
||||
fullpath = path.join(
|
||||
__dirname,
|
||||
"../..",
|
||||
file.substring("$ROOT/".length)
|
||||
);
|
||||
} else {
|
||||
fullpath = path.join(dir, file);
|
||||
}
|
||||
preprocess(fullpath, writeLine, defines);
|
||||
} catch (e) {
|
||||
if (e.code === 'ENOENT') {
|
||||
if (e.code === "ENOENT") {
|
||||
throw new Error('Failed to include "' + file + '" at ' + loc());
|
||||
}
|
||||
throw e; // Some other error
|
||||
@ -84,7 +100,7 @@ function preprocess(inFilename, outFilename, defines) {
|
||||
if (variable in defines) {
|
||||
return defines[variable];
|
||||
}
|
||||
return '';
|
||||
return "";
|
||||
});
|
||||
writeLine(line);
|
||||
}
|
||||
@ -104,104 +120,107 @@ function preprocess(inFilename, outFilename, defines) {
|
||||
var line;
|
||||
var state = STATE_NONE;
|
||||
var stack = [];
|
||||
var control = // eslint-disable-next-line max-len
|
||||
/^(?:\/\/|<!--)\s*#(if|elif|else|endif|expand|include|error)\b(?:\s+(.*?)(?:-->)?$)?/;
|
||||
var control = /^(?:\/\/|<!--)\s*#(if|elif|else|endif|expand|include|error)\b(?:\s+(.*?)(?:-->)?$)?/;
|
||||
var lineNumber = 0;
|
||||
var loc = function() {
|
||||
return fs.realpathSync(inFilename) + ':' + lineNumber;
|
||||
return fs.realpathSync(inFilename) + ":" + lineNumber;
|
||||
};
|
||||
while ((line = readLine()) !== null) {
|
||||
++lineNumber;
|
||||
var m = control.exec(line);
|
||||
if (m) {
|
||||
switch (m[1]) {
|
||||
case 'if':
|
||||
case "if":
|
||||
stack.push(state);
|
||||
state = evaluateCondition(m[2]) ? STATE_IF_TRUE : STATE_IF_FALSE;
|
||||
break;
|
||||
case 'elif':
|
||||
case "elif":
|
||||
if (state === STATE_IF_TRUE || state === STATE_ELSE_FALSE) {
|
||||
state = STATE_ELSE_FALSE;
|
||||
} else if (state === STATE_IF_FALSE) {
|
||||
state = evaluateCondition(m[2]) ? STATE_IF_TRUE : STATE_IF_FALSE;
|
||||
} else if (state === STATE_ELSE_TRUE) {
|
||||
throw new Error('Found #elif after #else at ' + loc());
|
||||
throw new Error("Found #elif after #else at " + loc());
|
||||
} else {
|
||||
throw new Error('Found #elif without matching #if at ' + loc());
|
||||
throw new Error("Found #elif without matching #if at " + loc());
|
||||
}
|
||||
break;
|
||||
case 'else':
|
||||
case "else":
|
||||
if (state === STATE_IF_TRUE || state === STATE_ELSE_FALSE) {
|
||||
state = STATE_ELSE_FALSE;
|
||||
} else if (state === STATE_IF_FALSE) {
|
||||
state = STATE_ELSE_TRUE;
|
||||
} else {
|
||||
throw new Error('Found #else without matching #if at ' + loc());
|
||||
throw new Error("Found #else without matching #if at " + loc());
|
||||
}
|
||||
break;
|
||||
case 'endif':
|
||||
case "endif":
|
||||
if (state === STATE_NONE) {
|
||||
throw new Error('Found #endif without #if at ' + loc());
|
||||
throw new Error("Found #endif without #if at " + loc());
|
||||
}
|
||||
state = stack.pop();
|
||||
break;
|
||||
case 'expand':
|
||||
case "expand":
|
||||
if (state !== STATE_IF_FALSE && state !== STATE_ELSE_FALSE) {
|
||||
expand(m[2]);
|
||||
}
|
||||
break;
|
||||
case 'include':
|
||||
case "include":
|
||||
if (state !== STATE_IF_FALSE && state !== STATE_ELSE_FALSE) {
|
||||
include(m[2]);
|
||||
}
|
||||
break;
|
||||
case 'error':
|
||||
case "error":
|
||||
if (state !== STATE_IF_FALSE && state !== STATE_ELSE_FALSE) {
|
||||
throw new Error('Found #error ' + m[2] + ' at ' + loc());
|
||||
throw new Error("Found #error " + m[2] + " at " + loc());
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (state === STATE_NONE) {
|
||||
writeLine(line);
|
||||
} else if ((state === STATE_IF_TRUE || state === STATE_ELSE_TRUE) &&
|
||||
!stack.includes(STATE_IF_FALSE) &&
|
||||
!stack.includes(STATE_ELSE_FALSE)) {
|
||||
writeLine(line.replace(/^\/\/|^<!--|-->$/g, ' '));
|
||||
} else if (
|
||||
(state === STATE_IF_TRUE || state === STATE_ELSE_TRUE) &&
|
||||
!stack.includes(STATE_IF_FALSE) &&
|
||||
!stack.includes(STATE_ELSE_FALSE)
|
||||
) {
|
||||
writeLine(line.replace(/^\/\/|^<!--|-->$/g, " "));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (state !== STATE_NONE || stack.length !== 0) {
|
||||
throw new Error('Missing #endif in preprocessor for ' +
|
||||
fs.realpathSync(inFilename));
|
||||
throw new Error(
|
||||
"Missing #endif in preprocessor for " + fs.realpathSync(inFilename)
|
||||
);
|
||||
}
|
||||
if (typeof outFilename !== 'function') {
|
||||
if (typeof outFilename !== "function") {
|
||||
fs.writeFileSync(outFilename, out);
|
||||
}
|
||||
}
|
||||
exports.preprocess = preprocess;
|
||||
|
||||
var deprecatedInMozcentral = new RegExp('(^|\\W)(' + [
|
||||
'-moz-box-sizing',
|
||||
'-moz-grab',
|
||||
'-moz-grabbing'
|
||||
].join('|') + ')');
|
||||
var deprecatedInMozcentral = new RegExp(
|
||||
"(^|\\W)(" + ["-moz-box-sizing", "-moz-grab", "-moz-grabbing"].join("|") + ")"
|
||||
);
|
||||
|
||||
function preprocessCSS(mode, source, destination) {
|
||||
function hasPrefixedFirefox(line) {
|
||||
return (/(^|\W)-(ms|o|webkit)-\w/.test(line));
|
||||
return /(^|\W)-(ms|o|webkit)-\w/.test(line);
|
||||
}
|
||||
|
||||
function hasPrefixedMozcentral(line) {
|
||||
return (/(^|\W)-(ms|o|webkit)-\w/.test(line) ||
|
||||
deprecatedInMozcentral.test(line));
|
||||
return (
|
||||
/(^|\W)-(ms|o|webkit)-\w/.test(line) || deprecatedInMozcentral.test(line)
|
||||
);
|
||||
}
|
||||
|
||||
function expandImports(content, baseUrl) {
|
||||
return content.replace(/^\s*@import\s+url\(([^\)]+)\);\s*$/gm,
|
||||
function(all, url) {
|
||||
return content.replace(/^\s*@import\s+url\(([^\)]+)\);\s*$/gm, function(
|
||||
all,
|
||||
url
|
||||
) {
|
||||
var file = path.join(path.dirname(baseUrl), url);
|
||||
var imported = fs.readFileSync(file, 'utf8').toString();
|
||||
var imported = fs.readFileSync(file, "utf8").toString();
|
||||
return expandImports(imported, file);
|
||||
});
|
||||
}
|
||||
@ -221,9 +240,9 @@ function preprocessCSS(mode, source, destination) {
|
||||
while (j < lines.length && bracketLevel > 0) {
|
||||
var checkBracket = /([{}])\s*$/.exec(lines[j]);
|
||||
if (checkBracket) {
|
||||
if (checkBracket[1] === '{') {
|
||||
if (checkBracket[1] === "{") {
|
||||
bracketLevel++;
|
||||
} else if (!lines[j].includes('{')) {
|
||||
} else if (!lines[j].includes("{")) {
|
||||
bracketLevel--;
|
||||
}
|
||||
}
|
||||
@ -236,30 +255,34 @@ function preprocessCSS(mode, source, destination) {
|
||||
// multiline? skipping until next directive or bracket
|
||||
do {
|
||||
lines.splice(i, 1);
|
||||
} while (i < lines.length &&
|
||||
!/\}\s*$/.test(lines[i]) &&
|
||||
!lines[i].includes(':'));
|
||||
} while (
|
||||
i < lines.length &&
|
||||
!/\}\s*$/.test(lines[i]) &&
|
||||
!lines[i].includes(":")
|
||||
);
|
||||
if (i < lines.length && /\S\s*}\s*$/.test(lines[i])) {
|
||||
lines[i] = lines[i].substring(lines[i].indexOf('}'));
|
||||
lines[i] = lines[i].substring(lines[i].indexOf("}"));
|
||||
}
|
||||
}
|
||||
// collapse whitespaces
|
||||
while (lines[i] === '' && lines[i - 1] === '') {
|
||||
while (lines[i] === "" && lines[i - 1] === "") {
|
||||
lines.splice(i, 1);
|
||||
}
|
||||
}
|
||||
return lines.join('\n');
|
||||
return lines.join("\n");
|
||||
}
|
||||
|
||||
if (!mode) {
|
||||
throw new Error('Invalid CSS preprocessor mode');
|
||||
throw new Error("Invalid CSS preprocessor mode");
|
||||
}
|
||||
|
||||
var content = fs.readFileSync(source, 'utf8').toString();
|
||||
var content = fs.readFileSync(source, "utf8").toString();
|
||||
content = expandImports(content, source);
|
||||
if (mode === 'mozcentral' || mode === 'firefox') {
|
||||
content = removePrefixed(content, mode === 'mozcentral' ?
|
||||
hasPrefixedMozcentral : hasPrefixedFirefox);
|
||||
if (mode === "mozcentral" || mode === "firefox") {
|
||||
content = removePrefixed(
|
||||
content,
|
||||
mode === "mozcentral" ? hasPrefixedMozcentral : hasPrefixedFirefox
|
||||
);
|
||||
}
|
||||
fs.writeFileSync(destination, content);
|
||||
}
|
||||
|
252
external/builder/preprocessor2.js
vendored
252
external/builder/preprocessor2.js
vendored
@ -1,103 +1,117 @@
|
||||
'use strict';
|
||||
"use strict";
|
||||
|
||||
var acorn = require('acorn');
|
||||
var escodegen = require('escodegen');
|
||||
var vm = require('vm');
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var acorn = require("acorn");
|
||||
var escodegen = require("escodegen");
|
||||
var vm = require("vm");
|
||||
var fs = require("fs");
|
||||
var path = require("path");
|
||||
|
||||
var PDFJS_PREPROCESSOR_NAME = 'PDFJSDev';
|
||||
var ROOT_PREFIX = '$ROOT/';
|
||||
var PDFJS_PREPROCESSOR_NAME = "PDFJSDev";
|
||||
var ROOT_PREFIX = "$ROOT/";
|
||||
|
||||
function isLiteral(obj, value) {
|
||||
return obj.type === 'Literal' && obj.value === value;
|
||||
return obj.type === "Literal" && obj.value === value;
|
||||
}
|
||||
|
||||
function isPDFJSPreprocessor(obj) {
|
||||
return obj.type === 'Identifier' &&
|
||||
obj.name === PDFJS_PREPROCESSOR_NAME;
|
||||
return obj.type === "Identifier" && obj.name === PDFJS_PREPROCESSOR_NAME;
|
||||
}
|
||||
|
||||
function evalWithDefines(code, defines, loc) {
|
||||
if (!code || !code.trim()) {
|
||||
throw new Error('No JavaScript expression given');
|
||||
throw new Error("No JavaScript expression given");
|
||||
}
|
||||
return vm.runInNewContext(code, defines, { displayErrors: false, });
|
||||
return vm.runInNewContext(code, defines, { displayErrors: false });
|
||||
}
|
||||
|
||||
function handlePreprocessorAction(ctx, actionName, args, loc) {
|
||||
try {
|
||||
var arg;
|
||||
switch (actionName) {
|
||||
case 'test':
|
||||
case "test":
|
||||
arg = args[0];
|
||||
if (!arg || arg.type !== 'Literal' ||
|
||||
typeof arg.value !== 'string') {
|
||||
throw new Error('No code for testing is given');
|
||||
if (!arg || arg.type !== "Literal" || typeof arg.value !== "string") {
|
||||
throw new Error("No code for testing is given");
|
||||
}
|
||||
var isTrue = !!evalWithDefines(arg.value, ctx.defines);
|
||||
return { type: 'Literal', value: isTrue, loc: loc, };
|
||||
case 'eval':
|
||||
return { type: "Literal", value: isTrue, loc: loc };
|
||||
case "eval":
|
||||
arg = args[0];
|
||||
if (!arg || arg.type !== 'Literal' ||
|
||||
typeof arg.value !== 'string') {
|
||||
throw new Error('No code for eval is given');
|
||||
if (!arg || arg.type !== "Literal" || typeof arg.value !== "string") {
|
||||
throw new Error("No code for eval is given");
|
||||
}
|
||||
var result = evalWithDefines(arg.value, ctx.defines);
|
||||
if (typeof result === 'boolean' || typeof result === 'string' ||
|
||||
typeof result === 'number') {
|
||||
return { type: 'Literal', value: result, loc: loc, };
|
||||
if (
|
||||
typeof result === "boolean" ||
|
||||
typeof result === "string" ||
|
||||
typeof result === "number"
|
||||
) {
|
||||
return { type: "Literal", value: result, loc: loc };
|
||||
}
|
||||
if (typeof result === 'object') {
|
||||
var parsedObj = acorn.parse('(' + JSON.stringify(result) + ')');
|
||||
if (typeof result === "object") {
|
||||
var parsedObj = acorn.parse("(" + JSON.stringify(result) + ")");
|
||||
parsedObj.body[0].expression.loc = loc;
|
||||
return parsedObj.body[0].expression;
|
||||
}
|
||||
break;
|
||||
case 'json':
|
||||
case "json":
|
||||
arg = args[0];
|
||||
if (!arg || arg.type !== 'Literal' ||
|
||||
typeof arg.value !== 'string') {
|
||||
throw new Error('Path to JSON is not provided');
|
||||
if (!arg || arg.type !== "Literal" || typeof arg.value !== "string") {
|
||||
throw new Error("Path to JSON is not provided");
|
||||
}
|
||||
var jsonPath = arg.value;
|
||||
if (jsonPath.indexOf(ROOT_PREFIX) === 0) {
|
||||
jsonPath = path.join(ctx.rootPath,
|
||||
jsonPath.substring(ROOT_PREFIX.length));
|
||||
jsonPath = path.join(
|
||||
ctx.rootPath,
|
||||
jsonPath.substring(ROOT_PREFIX.length)
|
||||
);
|
||||
}
|
||||
var jsonContent = fs.readFileSync(jsonPath).toString();
|
||||
var parsedJSON = acorn.parse('(' + jsonContent + ')');
|
||||
var parsedJSON = acorn.parse("(" + jsonContent + ")");
|
||||
parsedJSON.body[0].expression.loc = loc;
|
||||
return parsedJSON.body[0].expression;
|
||||
}
|
||||
throw new Error('Unsupported action');
|
||||
throw new Error("Unsupported action");
|
||||
} catch (e) {
|
||||
throw new Error('Could not process ' + PDFJS_PREPROCESSOR_NAME + '.' +
|
||||
actionName + ' at ' + JSON.stringify(loc) + '\n' +
|
||||
e.name + ': ' + e.message);
|
||||
throw new Error(
|
||||
"Could not process " +
|
||||
PDFJS_PREPROCESSOR_NAME +
|
||||
"." +
|
||||
actionName +
|
||||
" at " +
|
||||
JSON.stringify(loc) +
|
||||
"\n" +
|
||||
e.name +
|
||||
": " +
|
||||
e.message
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function postprocessNode(ctx, node) {
|
||||
switch (node.type) {
|
||||
case 'ExportNamedDeclaration':
|
||||
case 'ImportDeclaration':
|
||||
if (node.source && node.source.type === 'Literal' &&
|
||||
ctx.map && ctx.map[node.source.value]) {
|
||||
case "ExportNamedDeclaration":
|
||||
case "ImportDeclaration":
|
||||
if (
|
||||
node.source &&
|
||||
node.source.type === "Literal" &&
|
||||
ctx.map &&
|
||||
ctx.map[node.source.value]
|
||||
) {
|
||||
var newValue = ctx.map[node.source.value];
|
||||
node.source.value = node.source.raw = newValue;
|
||||
}
|
||||
break;
|
||||
case 'IfStatement':
|
||||
case "IfStatement":
|
||||
if (isLiteral(node.test, true)) {
|
||||
// if (true) stmt1; => stmt1
|
||||
return node.consequent;
|
||||
} else if (isLiteral(node.test, false)) {
|
||||
// if (false) stmt1; else stmt2; => stmt2
|
||||
return node.alternate || { type: 'EmptyStatement', loc: node.loc, };
|
||||
return node.alternate || { type: "EmptyStatement", loc: node.loc };
|
||||
}
|
||||
break;
|
||||
case 'ConditionalExpression':
|
||||
case "ConditionalExpression":
|
||||
if (isLiteral(node.test, true)) {
|
||||
// true ? stmt1 : stmt2 => stmt1
|
||||
return node.consequent;
|
||||
@ -106,22 +120,23 @@ function postprocessNode(ctx, node) {
|
||||
return node.alternate;
|
||||
}
|
||||
break;
|
||||
case 'UnaryExpression':
|
||||
if (node.operator === 'typeof' &&
|
||||
isPDFJSPreprocessor(node.argument)) {
|
||||
case "UnaryExpression":
|
||||
if (node.operator === "typeof" && isPDFJSPreprocessor(node.argument)) {
|
||||
// typeof PDFJSDev => 'object'
|
||||
return { type: 'Literal', value: 'object', loc: node.loc, };
|
||||
return { type: "Literal", value: "object", loc: node.loc };
|
||||
}
|
||||
if (node.operator === '!' &&
|
||||
node.argument.type === 'Literal' &&
|
||||
typeof node.argument.value === 'boolean') {
|
||||
if (
|
||||
node.operator === "!" &&
|
||||
node.argument.type === "Literal" &&
|
||||
typeof node.argument.value === "boolean"
|
||||
) {
|
||||
// !true => false, !false => true
|
||||
return { type: 'Literal', value: !node.argument.value, loc: node.loc, };
|
||||
return { type: "Literal", value: !node.argument.value, loc: node.loc };
|
||||
}
|
||||
break;
|
||||
case 'LogicalExpression':
|
||||
case "LogicalExpression":
|
||||
switch (node.operator) {
|
||||
case '&&':
|
||||
case "&&":
|
||||
if (isLiteral(node.left, true)) {
|
||||
return node.right;
|
||||
}
|
||||
@ -129,7 +144,7 @@ function postprocessNode(ctx, node) {
|
||||
return node.left;
|
||||
}
|
||||
break;
|
||||
case '||':
|
||||
case "||":
|
||||
if (isLiteral(node.left, true)) {
|
||||
return node.left;
|
||||
}
|
||||
@ -139,79 +154,93 @@ function postprocessNode(ctx, node) {
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'BinaryExpression':
|
||||
case "BinaryExpression":
|
||||
switch (node.operator) {
|
||||
case '==':
|
||||
case '===':
|
||||
case '!=':
|
||||
case '!==':
|
||||
if (node.left.type === 'Literal' &&
|
||||
node.right.type === 'Literal' &&
|
||||
typeof node.left.value === typeof node.right.value) {
|
||||
// folding two literals == and != check
|
||||
switch (typeof node.left.value) {
|
||||
case 'string':
|
||||
case 'boolean':
|
||||
case 'number':
|
||||
var equal = node.left.value === node.right.value;
|
||||
return {
|
||||
type: 'Literal',
|
||||
value: (node.operator[0] === '=') === equal,
|
||||
loc: node.loc,
|
||||
};
|
||||
}
|
||||
case "==":
|
||||
case "===":
|
||||
case "!=":
|
||||
case "!==":
|
||||
if (
|
||||
node.left.type === "Literal" &&
|
||||
node.right.type === "Literal" &&
|
||||
typeof node.left.value === typeof node.right.value
|
||||
) {
|
||||
// folding two literals == and != check
|
||||
switch (typeof node.left.value) {
|
||||
case "string":
|
||||
case "boolean":
|
||||
case "number":
|
||||
var equal = node.left.value === node.right.value;
|
||||
return {
|
||||
type: "Literal",
|
||||
value: (node.operator[0] === "=") === equal,
|
||||
loc: node.loc,
|
||||
};
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'CallExpression':
|
||||
if (node.callee.type === 'MemberExpression' &&
|
||||
isPDFJSPreprocessor(node.callee.object) &&
|
||||
node.callee.property.type === 'Identifier') {
|
||||
case "CallExpression":
|
||||
if (
|
||||
node.callee.type === "MemberExpression" &&
|
||||
isPDFJSPreprocessor(node.callee.object) &&
|
||||
node.callee.property.type === "Identifier"
|
||||
) {
|
||||
// PDFJSDev.xxxx(arg1, arg2, ...) => transform
|
||||
var action = node.callee.property.name;
|
||||
return handlePreprocessorAction(ctx, action,
|
||||
node.arguments, node.loc);
|
||||
return handlePreprocessorAction(ctx, action, node.arguments, node.loc);
|
||||
}
|
||||
// require('string')
|
||||
if (node.callee.type === 'Identifier' && node.callee.name === 'require' &&
|
||||
node.arguments.length === 1 && node.arguments[0].type === 'Literal' &&
|
||||
ctx.map && ctx.map[node.arguments[0].value]) {
|
||||
if (
|
||||
node.callee.type === "Identifier" &&
|
||||
node.callee.name === "require" &&
|
||||
node.arguments.length === 1 &&
|
||||
node.arguments[0].type === "Literal" &&
|
||||
ctx.map &&
|
||||
ctx.map[node.arguments[0].value]
|
||||
) {
|
||||
var requireName = node.arguments[0];
|
||||
requireName.value = requireName.raw = ctx.map[requireName.value];
|
||||
}
|
||||
break;
|
||||
case 'BlockStatement':
|
||||
case "BlockStatement":
|
||||
var subExpressionIndex = 0;
|
||||
while (subExpressionIndex < node.body.length) {
|
||||
switch (node.body[subExpressionIndex].type) {
|
||||
case 'EmptyStatement':
|
||||
case "EmptyStatement":
|
||||
// Removing empty statements from the blocks.
|
||||
node.body.splice(subExpressionIndex, 1);
|
||||
continue;
|
||||
case 'BlockStatement':
|
||||
case "BlockStatement":
|
||||
// Block statements inside a block are moved to the parent one.
|
||||
var subChildren = node.body[subExpressionIndex].body;
|
||||
Array.prototype.splice.apply(node.body,
|
||||
[subExpressionIndex, 1].concat(subChildren));
|
||||
Array.prototype.splice.apply(
|
||||
node.body,
|
||||
[subExpressionIndex, 1].concat(subChildren)
|
||||
);
|
||||
subExpressionIndex += Math.max(subChildren.length - 1, 0);
|
||||
continue;
|
||||
case 'ReturnStatement':
|
||||
case 'ThrowStatement':
|
||||
case "ReturnStatement":
|
||||
case "ThrowStatement":
|
||||
// Removing dead code after return or throw.
|
||||
node.body.splice(subExpressionIndex + 1,
|
||||
node.body.length - subExpressionIndex - 1);
|
||||
node.body.splice(
|
||||
subExpressionIndex + 1,
|
||||
node.body.length - subExpressionIndex - 1
|
||||
);
|
||||
break;
|
||||
}
|
||||
subExpressionIndex++;
|
||||
}
|
||||
break;
|
||||
case 'FunctionDeclaration':
|
||||
case 'FunctionExpression':
|
||||
case "FunctionDeclaration":
|
||||
case "FunctionExpression":
|
||||
var block = node.body;
|
||||
if (block.body.length > 0 &&
|
||||
block.body[block.body.length - 1].type === 'ReturnStatement' &&
|
||||
!block.body[block.body.length - 1].argument) {
|
||||
if (
|
||||
block.body.length > 0 &&
|
||||
block.body[block.body.length - 1].type === "ReturnStatement" &&
|
||||
!block.body[block.body.length - 1].argument
|
||||
) {
|
||||
// Function body ends with return without arg -- removing it.
|
||||
block.body.pop();
|
||||
}
|
||||
@ -237,14 +266,16 @@ function fixComments(ctx, node) {
|
||||
var type = node.leadingComments[i].type;
|
||||
var value = node.leadingComments[i].value;
|
||||
|
||||
if (ctx.saveComments === 'copyright') {
|
||||
if (ctx.saveComments === "copyright") {
|
||||
// Remove all comments, except Copyright notices and License headers.
|
||||
if (!(type === 'Block' && CopyrightRegExp.test(value))) {
|
||||
if (!(type === "Block" && CopyrightRegExp.test(value))) {
|
||||
node.leadingComments.splice(i, 1);
|
||||
continue;
|
||||
}
|
||||
} else if ((type === 'Block' && BlockCommentRegExp.test(value)) ||
|
||||
(type === 'Line' && LineCommentRegExp.test(value))) {
|
||||
} else if (
|
||||
(type === "Block" && BlockCommentRegExp.test(value)) ||
|
||||
(type === "Line" && LineCommentRegExp.test(value))
|
||||
) {
|
||||
node.leadingComments.splice(i, 1);
|
||||
continue;
|
||||
}
|
||||
@ -257,15 +288,18 @@ function traverseTree(ctx, node) {
|
||||
// generic node processing
|
||||
for (var i in node) {
|
||||
var child = node[i];
|
||||
if (typeof child === 'object' && child !== null && child.type) {
|
||||
if (typeof child === "object" && child !== null && child.type) {
|
||||
var result = traverseTree(ctx, child);
|
||||
if (result !== child) {
|
||||
node[i] = result;
|
||||
}
|
||||
} else if (Array.isArray(child)) {
|
||||
child.forEach(function (childItem, index) {
|
||||
if (typeof childItem === 'object' && childItem !== null &&
|
||||
childItem.type) {
|
||||
child.forEach(function(childItem, index) {
|
||||
if (
|
||||
typeof childItem === "object" &&
|
||||
childItem !== null &&
|
||||
childItem.type
|
||||
) {
|
||||
var result = traverseTree(ctx, childItem);
|
||||
if (result !== childItem) {
|
||||
child[index] = result;
|
||||
@ -284,14 +318,14 @@ function traverseTree(ctx, node) {
|
||||
function preprocessPDFJSCode(ctx, code) {
|
||||
var format = ctx.format || {
|
||||
indent: {
|
||||
style: ' ',
|
||||
style: " ",
|
||||
},
|
||||
};
|
||||
var parseOptions = {
|
||||
ecmaVersion: 8,
|
||||
locations: true,
|
||||
sourceFile: ctx.sourceFile,
|
||||
sourceType: 'module',
|
||||
sourceType: "module",
|
||||
};
|
||||
var codegenOptions = {
|
||||
format: format,
|
||||
|
50
external/builder/test-fixtures.js
vendored
50
external/builder/test-fixtures.js
vendored
@ -1,20 +1,26 @@
|
||||
'use strict';
|
||||
"use strict";
|
||||
|
||||
var builder = require('./builder');
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var builder = require("./builder");
|
||||
var fs = require("fs");
|
||||
var path = require("path");
|
||||
|
||||
var errors = 0;
|
||||
|
||||
var baseDir = path.join(__dirname, 'fixtures');
|
||||
var files = fs.readdirSync(baseDir).filter(function (name) {
|
||||
return /-expected\./.test(name);
|
||||
}).map(function (name) {
|
||||
return path.join(baseDir, name);
|
||||
});
|
||||
var baseDir = path.join(__dirname, "fixtures");
|
||||
var files = fs
|
||||
.readdirSync(baseDir)
|
||||
.filter(function(name) {
|
||||
return /-expected\./.test(name);
|
||||
})
|
||||
.map(function(name) {
|
||||
return path.join(baseDir, name);
|
||||
});
|
||||
files.forEach(function(expectationFilename) {
|
||||
var inFilename = expectationFilename.replace('-expected', '');
|
||||
var expectation = fs.readFileSync(expectationFilename).toString().trim()
|
||||
var inFilename = expectationFilename.replace("-expected", "");
|
||||
var expectation = fs
|
||||
.readFileSync(expectationFilename)
|
||||
.toString()
|
||||
.trim()
|
||||
.replace(/__filename/g, fs.realpathSync(inFilename));
|
||||
var outLines = [];
|
||||
|
||||
@ -28,29 +34,29 @@ files.forEach(function(expectationFilename) {
|
||||
var out;
|
||||
try {
|
||||
builder.preprocess(inFilename, outFilename, defines);
|
||||
out = outLines.join('\n').trim();
|
||||
out = outLines.join("\n").trim();
|
||||
} catch (e) {
|
||||
out = ('Error: ' + e.message).replace(/^/gm, '//');
|
||||
out = ("Error: " + e.message).replace(/^/gm, "//");
|
||||
}
|
||||
if (out !== expectation) {
|
||||
errors++;
|
||||
|
||||
console.log('Assertion failed for ' + inFilename);
|
||||
console.log('--------------------------------------------------');
|
||||
console.log('EXPECTED:');
|
||||
console.log("Assertion failed for " + inFilename);
|
||||
console.log("--------------------------------------------------");
|
||||
console.log("EXPECTED:");
|
||||
console.log(expectation);
|
||||
console.log('--------------------------------------------------');
|
||||
console.log('ACTUAL');
|
||||
console.log("--------------------------------------------------");
|
||||
console.log("ACTUAL");
|
||||
console.log(out);
|
||||
console.log('--------------------------------------------------');
|
||||
console.log("--------------------------------------------------");
|
||||
console.log();
|
||||
}
|
||||
});
|
||||
|
||||
if (errors) {
|
||||
console.error('Found ' + errors + ' expectation failures.');
|
||||
console.error("Found " + errors + " expectation failures.");
|
||||
process.exit(1);
|
||||
} else {
|
||||
console.log('All tests completed without errors.');
|
||||
console.log("All tests completed without errors.");
|
||||
process.exit(0);
|
||||
}
|
||||
|
56
external/builder/test-fixtures_esprima.js
vendored
56
external/builder/test-fixtures_esprima.js
vendored
@ -1,62 +1,68 @@
|
||||
'use strict';
|
||||
"use strict";
|
||||
|
||||
var p2 = require('./preprocessor2.js');
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var p2 = require("./preprocessor2.js");
|
||||
var fs = require("fs");
|
||||
var path = require("path");
|
||||
|
||||
var errors = 0;
|
||||
|
||||
var baseDir = path.join(__dirname, 'fixtures_esprima');
|
||||
var files = fs.readdirSync(baseDir).filter(function (name) {
|
||||
return /-expected\./.test(name);
|
||||
}).map(function (name) {
|
||||
return path.join(baseDir, name);
|
||||
});
|
||||
var baseDir = path.join(__dirname, "fixtures_esprima");
|
||||
var files = fs
|
||||
.readdirSync(baseDir)
|
||||
.filter(function(name) {
|
||||
return /-expected\./.test(name);
|
||||
})
|
||||
.map(function(name) {
|
||||
return path.join(baseDir, name);
|
||||
});
|
||||
files.forEach(function(expectationFilename) {
|
||||
var inFilename = expectationFilename.replace('-expected', '');
|
||||
var expectation = fs.readFileSync(expectationFilename).toString().trim()
|
||||
var inFilename = expectationFilename.replace("-expected", "");
|
||||
var expectation = fs
|
||||
.readFileSync(expectationFilename)
|
||||
.toString()
|
||||
.trim()
|
||||
.replace(/__filename/g, fs.realpathSync(inFilename));
|
||||
var input = fs.readFileSync(inFilename).toString();
|
||||
|
||||
var defines = {
|
||||
TRUE: true,
|
||||
FALSE: false,
|
||||
OBJ: { obj: { i: 1, }, j: 2, },
|
||||
TEXT: 'text',
|
||||
OBJ: { obj: { i: 1 }, j: 2 },
|
||||
TEXT: "text",
|
||||
};
|
||||
var map = {
|
||||
'import-alias': 'import-name',
|
||||
"import-alias": "import-name",
|
||||
};
|
||||
var ctx = {
|
||||
defines: defines,
|
||||
map: map,
|
||||
rootPath: __dirname + '/../..',
|
||||
rootPath: __dirname + "/../..",
|
||||
};
|
||||
var out;
|
||||
try {
|
||||
out = p2.preprocessPDFJSCode(ctx, input);
|
||||
} catch (e) {
|
||||
out = ('Error: ' + e.message).replace(/^/gm, '//');
|
||||
out = ("Error: " + e.message).replace(/^/gm, "//");
|
||||
}
|
||||
if (out !== expectation) {
|
||||
errors++;
|
||||
|
||||
console.log('Assertion failed for ' + inFilename);
|
||||
console.log('--------------------------------------------------');
|
||||
console.log('EXPECTED:');
|
||||
console.log("Assertion failed for " + inFilename);
|
||||
console.log("--------------------------------------------------");
|
||||
console.log("EXPECTED:");
|
||||
console.log(expectation);
|
||||
console.log('--------------------------------------------------');
|
||||
console.log('ACTUAL');
|
||||
console.log("--------------------------------------------------");
|
||||
console.log("ACTUAL");
|
||||
console.log(out);
|
||||
console.log('--------------------------------------------------');
|
||||
console.log("--------------------------------------------------");
|
||||
console.log();
|
||||
}
|
||||
});
|
||||
|
||||
if (errors) {
|
||||
console.error('Found ' + errors + ' expectation failures.');
|
||||
console.error("Found " + errors + " expectation failures.");
|
||||
process.exit(1);
|
||||
} else {
|
||||
console.log('All tests completed without errors.');
|
||||
console.log("All tests completed without errors.");
|
||||
process.exit(0);
|
||||
}
|
||||
|
8
external/dist/webpack.js
vendored
8
external/dist/webpack.js
vendored
@ -12,12 +12,12 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
'use strict';
|
||||
"use strict";
|
||||
|
||||
var pdfjs = require('./build/pdf.js');
|
||||
var PdfjsWorker = require('worker-loader!./build/pdf.worker.js');
|
||||
var pdfjs = require("./build/pdf.js");
|
||||
var PdfjsWorker = require("worker-loader!./build/pdf.worker.js");
|
||||
|
||||
if (typeof window !== 'undefined' && 'Worker' in window) {
|
||||
if (typeof window !== "undefined" && "Worker" in window) {
|
||||
pdfjs.GlobalWorkerOptions.workerPort = new PdfjsWorker();
|
||||
}
|
||||
|
||||
|
64
external/importL10n/locales.js
vendored
64
external/importL10n/locales.js
vendored
@ -13,39 +13,40 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
"use strict";
|
||||
|
||||
var fs = require('fs');
|
||||
var https = require('https');
|
||||
var path = require('path');
|
||||
var fs = require("fs");
|
||||
var https = require("https");
|
||||
var path = require("path");
|
||||
|
||||
// Fetches all languages that have an *active* translation in mozilla-central.
|
||||
// This is used in gulpfile.js for the `importl10n` command.
|
||||
|
||||
var DEFAULT_LOCALE = 'en-US';
|
||||
var DEFAULT_LOCALE = "en-US";
|
||||
|
||||
var EXCLUDE_LANG_CODES = ['ca-valencia', 'ja-JP-mac'];
|
||||
var EXCLUDE_LANG_CODES = ["ca-valencia", "ja-JP-mac"];
|
||||
|
||||
function normalizeText(s) {
|
||||
return s.replace(/\r\n?/g, '\n').replace(/\uFEFF/g, '');
|
||||
return s.replace(/\r\n?/g, "\n").replace(/\uFEFF/g, "");
|
||||
}
|
||||
|
||||
function downloadLanguageCodes() {
|
||||
console.log('Downloading language codes...\n');
|
||||
console.log("Downloading language codes...\n");
|
||||
|
||||
var ALL_LOCALES = 'https://hg.mozilla.org/mozilla-central/raw-file/tip/browser/locales/all-locales';
|
||||
var ALL_LOCALES =
|
||||
"https://hg.mozilla.org/mozilla-central/raw-file/tip/browser/locales/all-locales";
|
||||
|
||||
return new Promise(function(resolve) {
|
||||
https.get(ALL_LOCALES, function(response) {
|
||||
if (response.statusCode === 200) {
|
||||
var content = '';
|
||||
response.setEncoding('utf8');
|
||||
response.on('data', function(chunk) {
|
||||
var content = "";
|
||||
response.setEncoding("utf8");
|
||||
response.on("data", function(chunk) {
|
||||
content += chunk;
|
||||
});
|
||||
response.on('end', function() {
|
||||
response.on("end", function() {
|
||||
content = content.trim(); // Remove any leading/trailing white-space.
|
||||
var langCodes = normalizeText(content).split('\n');
|
||||
var langCodes = normalizeText(content).split("\n");
|
||||
// Remove all locales that we don't want to download below.
|
||||
for (var langCode of [DEFAULT_LOCALE, ...EXCLUDE_LANG_CODES]) {
|
||||
var i = langCodes.indexOf(langCode);
|
||||
@ -63,15 +64,15 @@ function downloadLanguageCodes() {
|
||||
}
|
||||
|
||||
function downloadLanguageFiles(root, langCode) {
|
||||
console.log('Downloading ' + langCode + '...');
|
||||
console.log("Downloading " + langCode + "...");
|
||||
|
||||
// Constants for constructing the URLs. Translations are taken from the
|
||||
// Nightly channel as those are the most recent ones.
|
||||
var MOZ_CENTRAL_ROOT = 'https://hg.mozilla.org/l10n-central/';
|
||||
var MOZ_CENTRAL_PDFJS_DIR = '/raw-file/default/browser/pdfviewer/';
|
||||
var MOZ_CENTRAL_ROOT = "https://hg.mozilla.org/l10n-central/";
|
||||
var MOZ_CENTRAL_PDFJS_DIR = "/raw-file/default/browser/pdfviewer/";
|
||||
|
||||
// Defines which files to download for each language.
|
||||
var files = ['viewer.properties'];
|
||||
var files = ["viewer.properties"];
|
||||
var downloadsLeft = files.length;
|
||||
|
||||
var outputDir = path.join(root, langCode);
|
||||
@ -89,13 +90,13 @@ function downloadLanguageFiles(root, langCode) {
|
||||
// Not all files exist for each language. Files without translations
|
||||
// have been removed (https://bugzilla.mozilla.org/show_bug.cgi?id=1443175).
|
||||
if (response.statusCode === 200) {
|
||||
var content = '';
|
||||
response.setEncoding('utf8');
|
||||
response.on('data', function(chunk) {
|
||||
var content = "";
|
||||
response.setEncoding("utf8");
|
||||
response.on("data", function(chunk) {
|
||||
content += chunk;
|
||||
});
|
||||
response.on('end', function() {
|
||||
fs.writeFileSync(outputPath, normalizeText(content), 'utf8');
|
||||
response.on("end", function() {
|
||||
fs.writeFileSync(outputPath, normalizeText(content), "utf8");
|
||||
if (--downloadsLeft === 0) {
|
||||
resolve();
|
||||
}
|
||||
@ -122,16 +123,23 @@ async function downloadL10n(root, callback) {
|
||||
|
||||
var removeCodes = [];
|
||||
for (var entry of fs.readdirSync(root)) {
|
||||
var dirPath = path.join(root, entry), stat = fs.lstatSync(dirPath);
|
||||
var dirPath = path.join(root, entry),
|
||||
stat = fs.lstatSync(dirPath);
|
||||
|
||||
if (stat.isDirectory() && entry !== DEFAULT_LOCALE &&
|
||||
!langCodes.includes(entry)) {
|
||||
if (
|
||||
stat.isDirectory() &&
|
||||
entry !== DEFAULT_LOCALE &&
|
||||
!langCodes.includes(entry)
|
||||
) {
|
||||
removeCodes.push(entry);
|
||||
}
|
||||
}
|
||||
if (removeCodes.length) {
|
||||
console.log('\nConsider removing the following unmaintained locales:\n' +
|
||||
removeCodes.join(', ') + '\n');
|
||||
console.log(
|
||||
"\nConsider removing the following unmaintained locales:\n" +
|
||||
removeCodes.join(", ") +
|
||||
"\n"
|
||||
);
|
||||
}
|
||||
|
||||
if (callback) {
|
||||
|
125
external/systemjs/plugin-babel-cached.js
vendored
125
external/systemjs/plugin-babel-cached.js
vendored
@ -12,28 +12,28 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
var babel = require('plugin-babel');
|
||||
var babel = require("plugin-babel");
|
||||
|
||||
var cacheExpiration = 60 /* min */ * 60 * 1000;
|
||||
var dbVersion = 1;
|
||||
var dbName = 'babelcache';
|
||||
var dbCacheTable = 'translated';
|
||||
var dbName = "babelcache";
|
||||
var dbCacheTable = "translated";
|
||||
var dbPromise;
|
||||
|
||||
function getDb() {
|
||||
if (!dbPromise) {
|
||||
dbPromise = new Promise(function (resolve, reject) {
|
||||
dbPromise = new Promise(function(resolve, reject) {
|
||||
var request = indexedDB.open(dbName, dbVersion);
|
||||
request.onupgradeneeded = function() {
|
||||
var db = request.result;
|
||||
db.createObjectStore(dbCacheTable, { keyPath: 'address', });
|
||||
db.createObjectStore(dbCacheTable, { keyPath: "address" });
|
||||
};
|
||||
request.onsuccess = function() {
|
||||
var db = request.result;
|
||||
resolve(db);
|
||||
};
|
||||
request.onerror = function () {
|
||||
console.warn('getDb: ' + request.error);
|
||||
request.onerror = function() {
|
||||
console.warn("getDb: " + request.error);
|
||||
reject(request.error);
|
||||
};
|
||||
});
|
||||
@ -42,8 +42,8 @@ function getDb() {
|
||||
}
|
||||
|
||||
function storeCache(address, hashCode, translated, format) {
|
||||
return getDb().then(function (db) {
|
||||
var tx = db.transaction(dbCacheTable, 'readwrite');
|
||||
return getDb().then(function(db) {
|
||||
var tx = db.transaction(dbCacheTable, "readwrite");
|
||||
var store = tx.objectStore(dbCacheTable);
|
||||
store.put({
|
||||
address: address,
|
||||
@ -52,11 +52,11 @@ function storeCache(address, hashCode, translated, format) {
|
||||
expires: Date.now() + cacheExpiration,
|
||||
format: format,
|
||||
});
|
||||
return new Promise(function (resolve, reject) {
|
||||
tx.oncomplete = function () {
|
||||
return new Promise(function(resolve, reject) {
|
||||
tx.oncomplete = function() {
|
||||
resolve();
|
||||
};
|
||||
tx.onerror = function () {
|
||||
tx.onerror = function() {
|
||||
resolve();
|
||||
};
|
||||
});
|
||||
@ -64,59 +64,84 @@ function storeCache(address, hashCode, translated, format) {
|
||||
}
|
||||
|
||||
function loadCache(address, hashCode) {
|
||||
return getDb().then(function (db) {
|
||||
var tx = db.transaction(dbCacheTable, 'readonly');
|
||||
return getDb().then(function(db) {
|
||||
var tx = db.transaction(dbCacheTable, "readonly");
|
||||
var store = tx.objectStore(dbCacheTable);
|
||||
var getAddress = store.get(address);
|
||||
return new Promise(function (resolve, reject) {
|
||||
tx.oncomplete = function () {
|
||||
return new Promise(function(resolve, reject) {
|
||||
tx.oncomplete = function() {
|
||||
var found = getAddress.result;
|
||||
var isValid = found && found.hashCode === hashCode &&
|
||||
Date.now() < found.expires;
|
||||
resolve(isValid ? {
|
||||
translated: found.translated,
|
||||
format: found.format,
|
||||
} : null);
|
||||
var isValid =
|
||||
found && found.hashCode === hashCode && Date.now() < found.expires;
|
||||
resolve(
|
||||
isValid
|
||||
? {
|
||||
translated: found.translated,
|
||||
format: found.format,
|
||||
}
|
||||
: null
|
||||
);
|
||||
};
|
||||
tx.onerror = function () {
|
||||
tx.onerror = function() {
|
||||
resolve(null);
|
||||
};
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
var encoder = new TextEncoder('utf-8');
|
||||
var encoder = new TextEncoder("utf-8");
|
||||
function sha256(str) {
|
||||
var buffer = encoder.encode(str);
|
||||
return crypto.subtle.digest('SHA-256', buffer).then(function (hash) {
|
||||
return crypto.subtle.digest("SHA-256", buffer).then(function(hash) {
|
||||
var data = new Int32Array(hash);
|
||||
return data[0].toString(36) + '-' + data[1].toString(36) + '-' +
|
||||
data[2].toString(36) + '-' + data[3].toString(36);
|
||||
return (
|
||||
data[0].toString(36) +
|
||||
"-" +
|
||||
data[1].toString(36) +
|
||||
"-" +
|
||||
data[2].toString(36) +
|
||||
"-" +
|
||||
data[3].toString(36)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
exports.translate = function (load, opt) {
|
||||
exports.translate = function(load, opt) {
|
||||
var savedHashCode, babelTranslateError;
|
||||
return sha256(load.source).then(function (hashCode) {
|
||||
savedHashCode = hashCode;
|
||||
return loadCache(load.address, hashCode);
|
||||
}).then(function (cache) {
|
||||
if (cache) {
|
||||
load.metadata.format = cache.format;
|
||||
return cache.translated;
|
||||
}
|
||||
return babel.translate.call(this, load, opt).then(function(translated) {
|
||||
return storeCache(load.address, savedHashCode,
|
||||
translated, load.metadata.format).then(function () {
|
||||
return translated;
|
||||
});
|
||||
}, function(reason) {
|
||||
throw (babelTranslateError = reason);
|
||||
});
|
||||
}.bind(this)).catch(function(reason) {
|
||||
if (babelTranslateError) {
|
||||
throw babelTranslateError;
|
||||
}
|
||||
return babel.translate.call(this, load, opt);
|
||||
}.bind(this));
|
||||
return sha256(load.source)
|
||||
.then(function(hashCode) {
|
||||
savedHashCode = hashCode;
|
||||
return loadCache(load.address, hashCode);
|
||||
})
|
||||
.then(
|
||||
function(cache) {
|
||||
if (cache) {
|
||||
load.metadata.format = cache.format;
|
||||
return cache.translated;
|
||||
}
|
||||
return babel.translate.call(this, load, opt).then(
|
||||
function(translated) {
|
||||
return storeCache(
|
||||
load.address,
|
||||
savedHashCode,
|
||||
translated,
|
||||
load.metadata.format
|
||||
).then(function() {
|
||||
return translated;
|
||||
});
|
||||
},
|
||||
function(reason) {
|
||||
throw (babelTranslateError = reason);
|
||||
}
|
||||
);
|
||||
}.bind(this)
|
||||
)
|
||||
.catch(
|
||||
function(reason) {
|
||||
if (babelTranslateError) {
|
||||
throw babelTranslateError;
|
||||
}
|
||||
return babel.translate.call(this, load, opt);
|
||||
}.bind(this)
|
||||
);
|
||||
};
|
||||
|
13
external/webpack/pdfjsdev-loader.js
vendored
13
external/webpack/pdfjsdev-loader.js
vendored
@ -14,21 +14,24 @@
|
||||
*/
|
||||
/* eslint-env node */
|
||||
|
||||
'use strict';
|
||||
"use strict";
|
||||
|
||||
var preprocessor2 = require('../builder/preprocessor2.js');
|
||||
var path = require('path');
|
||||
var preprocessor2 = require("../builder/preprocessor2.js");
|
||||
var path = require("path");
|
||||
|
||||
module.exports = function(source) {
|
||||
// Options must be specified, ignoring request if not.
|
||||
if (!this.query || typeof this.query !== 'object') {
|
||||
if (!this.query || typeof this.query !== "object") {
|
||||
return source;
|
||||
}
|
||||
this.cacheable();
|
||||
|
||||
var filePath = this.resourcePath;
|
||||
var context = this.rootContext;
|
||||
var sourcePath = path.relative(context, filePath).split(path.sep).join('/');
|
||||
var sourcePath = path
|
||||
.relative(context, filePath)
|
||||
.split(path.sep)
|
||||
.join("/");
|
||||
|
||||
var ctx = Object.create(this.query);
|
||||
ctx.sourceMap = true;
|
||||
|
2028
gulpfile.js
2028
gulpfile.js
File diff suppressed because it is too large
Load Diff
@ -15,16 +15,25 @@
|
||||
/* eslint no-var: error */
|
||||
|
||||
import {
|
||||
AnnotationBorderStyleType, AnnotationFieldFlag, AnnotationFlag,
|
||||
AnnotationReplyType, AnnotationType, assert, isString, OPS, stringToBytes,
|
||||
stringToPDFString, Util, warn
|
||||
} from '../shared/util';
|
||||
import { Catalog, FileSpec, ObjectLoader } from './obj';
|
||||
import { Dict, isDict, isName, isRef, isStream } from './primitives';
|
||||
import { ColorSpace } from './colorspace';
|
||||
import { getInheritableProperty } from './core_utils';
|
||||
import { OperatorList } from './operator_list';
|
||||
import { Stream } from './stream';
|
||||
AnnotationBorderStyleType,
|
||||
AnnotationFieldFlag,
|
||||
AnnotationFlag,
|
||||
AnnotationReplyType,
|
||||
AnnotationType,
|
||||
assert,
|
||||
isString,
|
||||
OPS,
|
||||
stringToBytes,
|
||||
stringToPDFString,
|
||||
Util,
|
||||
warn,
|
||||
} from "../shared/util";
|
||||
import { Catalog, FileSpec, ObjectLoader } from "./obj";
|
||||
import { Dict, isDict, isName, isRef, isStream } from "./primitives";
|
||||
import { ColorSpace } from "./colorspace";
|
||||
import { getInheritableProperty } from "./core_utils";
|
||||
import { OperatorList } from "./operator_list";
|
||||
import { Stream } from "./stream";
|
||||
|
||||
class AnnotationFactory {
|
||||
/**
|
||||
@ -40,8 +49,12 @@ class AnnotationFactory {
|
||||
* instance.
|
||||
*/
|
||||
static create(xref, ref, pdfManager, idFactory) {
|
||||
return pdfManager.ensure(this, '_create',
|
||||
[xref, ref, pdfManager, idFactory]);
|
||||
return pdfManager.ensure(this, "_create", [
|
||||
xref,
|
||||
ref,
|
||||
pdfManager,
|
||||
idFactory,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -55,7 +68,7 @@ class AnnotationFactory {
|
||||
const id = isRef(ref) ? ref.toString() : `annot_${idFactory.createObjId()}`;
|
||||
|
||||
// Determine the annotation's subtype.
|
||||
let subtype = dict.get('Subtype');
|
||||
let subtype = dict.get("Subtype");
|
||||
subtype = isName(subtype) ? subtype.name : null;
|
||||
|
||||
// Return the right annotation object based on the subtype and field type.
|
||||
@ -68,79 +81,87 @@ class AnnotationFactory {
|
||||
};
|
||||
|
||||
switch (subtype) {
|
||||
case 'Link':
|
||||
case "Link":
|
||||
return new LinkAnnotation(parameters);
|
||||
|
||||
case 'Text':
|
||||
case "Text":
|
||||
return new TextAnnotation(parameters);
|
||||
|
||||
case 'Widget':
|
||||
let fieldType = getInheritableProperty({ dict, key: 'FT', });
|
||||
case "Widget":
|
||||
let fieldType = getInheritableProperty({ dict, key: "FT" });
|
||||
fieldType = isName(fieldType) ? fieldType.name : null;
|
||||
|
||||
switch (fieldType) {
|
||||
case 'Tx':
|
||||
case "Tx":
|
||||
return new TextWidgetAnnotation(parameters);
|
||||
case 'Btn':
|
||||
case "Btn":
|
||||
return new ButtonWidgetAnnotation(parameters);
|
||||
case 'Ch':
|
||||
case "Ch":
|
||||
return new ChoiceWidgetAnnotation(parameters);
|
||||
}
|
||||
warn('Unimplemented widget field type "' + fieldType + '", ' +
|
||||
'falling back to base field type.');
|
||||
warn(
|
||||
'Unimplemented widget field type "' +
|
||||
fieldType +
|
||||
'", ' +
|
||||
"falling back to base field type."
|
||||
);
|
||||
return new WidgetAnnotation(parameters);
|
||||
|
||||
case 'Popup':
|
||||
case "Popup":
|
||||
return new PopupAnnotation(parameters);
|
||||
|
||||
case 'FreeText':
|
||||
case "FreeText":
|
||||
return new FreeTextAnnotation(parameters);
|
||||
|
||||
case 'Line':
|
||||
case "Line":
|
||||
return new LineAnnotation(parameters);
|
||||
|
||||
case 'Square':
|
||||
case "Square":
|
||||
return new SquareAnnotation(parameters);
|
||||
|
||||
case 'Circle':
|
||||
case "Circle":
|
||||
return new CircleAnnotation(parameters);
|
||||
|
||||
case 'PolyLine':
|
||||
case "PolyLine":
|
||||
return new PolylineAnnotation(parameters);
|
||||
|
||||
case 'Polygon':
|
||||
case "Polygon":
|
||||
return new PolygonAnnotation(parameters);
|
||||
|
||||
case 'Caret':
|
||||
case "Caret":
|
||||
return new CaretAnnotation(parameters);
|
||||
|
||||
case 'Ink':
|
||||
case "Ink":
|
||||
return new InkAnnotation(parameters);
|
||||
|
||||
case 'Highlight':
|
||||
case "Highlight":
|
||||
return new HighlightAnnotation(parameters);
|
||||
|
||||
case 'Underline':
|
||||
case "Underline":
|
||||
return new UnderlineAnnotation(parameters);
|
||||
|
||||
case 'Squiggly':
|
||||
case "Squiggly":
|
||||
return new SquigglyAnnotation(parameters);
|
||||
|
||||
case 'StrikeOut':
|
||||
case "StrikeOut":
|
||||
return new StrikeOutAnnotation(parameters);
|
||||
|
||||
case 'Stamp':
|
||||
case "Stamp":
|
||||
return new StampAnnotation(parameters);
|
||||
|
||||
case 'FileAttachment':
|
||||
case "FileAttachment":
|
||||
return new FileAttachmentAnnotation(parameters);
|
||||
|
||||
default:
|
||||
if (!subtype) {
|
||||
warn('Annotation is missing the required /Subtype.');
|
||||
warn("Annotation is missing the required /Subtype.");
|
||||
} else {
|
||||
warn('Unimplemented annotation type "' + subtype + '", ' +
|
||||
'falling back to base annotation.');
|
||||
warn(
|
||||
'Unimplemented annotation type "' +
|
||||
subtype +
|
||||
'", ' +
|
||||
"falling back to base annotation."
|
||||
);
|
||||
}
|
||||
return new Annotation(parameters);
|
||||
}
|
||||
@ -148,13 +169,13 @@ class AnnotationFactory {
|
||||
}
|
||||
|
||||
function getQuadPoints(dict, rect) {
|
||||
if (!dict.has('QuadPoints')) {
|
||||
if (!dict.has("QuadPoints")) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// The region is described as a number of quadrilaterals.
|
||||
// Each quadrilateral must consist of eight coordinates.
|
||||
const quadPoints = dict.getArray('QuadPoints');
|
||||
const quadPoints = dict.getArray("QuadPoints");
|
||||
if (!Array.isArray(quadPoints) || quadPoints.length % 8 > 0) {
|
||||
return null;
|
||||
}
|
||||
@ -165,7 +186,7 @@ function getQuadPoints(dict, rect) {
|
||||
// quadrilateral in the order [x1, y1, x2, y2, x3, y3, x4, y4].
|
||||
// Convert this to an array of objects with x and y coordinates.
|
||||
quadPointsLists.push([]);
|
||||
for (let j = i * 8, jj = (i * 8) + 8; j < jj; j += 2) {
|
||||
for (let j = i * 8, jj = i * 8 + 8; j < jj; j += 2) {
|
||||
const x = quadPoints[j];
|
||||
const y = quadPoints[j + 1];
|
||||
|
||||
@ -174,7 +195,7 @@ function getQuadPoints(dict, rect) {
|
||||
if (x < rect[0] || x > rect[2] || y < rect[1] || y > rect[3]) {
|
||||
return null;
|
||||
}
|
||||
quadPointsLists[i].push({ x, y, });
|
||||
quadPointsLists[i].push({ x, y });
|
||||
}
|
||||
}
|
||||
return quadPointsLists;
|
||||
@ -182,8 +203,10 @@ function getQuadPoints(dict, rect) {
|
||||
|
||||
function getTransformMatrix(rect, bbox, matrix) {
|
||||
// 12.5.5: Algorithm: Appearance streams
|
||||
const [minX, minY, maxX, maxY] =
|
||||
Util.getAxialAlignedBoundingBox(bbox, matrix);
|
||||
const [minX, minY, maxX, maxY] = Util.getAxialAlignedBoundingBox(
|
||||
bbox,
|
||||
matrix
|
||||
);
|
||||
if (minX === maxX || minY === maxY) {
|
||||
// From real-life file, bbox was [0, 0, 0, 0]. In this case,
|
||||
// just apply the transform for rect
|
||||
@ -198,7 +221,7 @@ function getTransformMatrix(rect, bbox, matrix) {
|
||||
0,
|
||||
yRatio,
|
||||
rect[0] - minX * xRatio,
|
||||
rect[1] - minY * yRatio
|
||||
rect[1] - minY * yRatio,
|
||||
];
|
||||
}
|
||||
|
||||
@ -206,11 +229,11 @@ class Annotation {
|
||||
constructor(params) {
|
||||
const dict = params.dict;
|
||||
|
||||
this.setContents(dict.get('Contents'));
|
||||
this.setModificationDate(dict.get('M'));
|
||||
this.setFlags(dict.get('F'));
|
||||
this.setRectangle(dict.getArray('Rect'));
|
||||
this.setColor(dict.getArray('C'));
|
||||
this.setContents(dict.get("Contents"));
|
||||
this.setModificationDate(dict.get("M"));
|
||||
this.setFlags(dict.get("F"));
|
||||
this.setRectangle(dict.getArray("Rect"));
|
||||
this.setColor(dict.getArray("C"));
|
||||
this.setBorderStyle(dict);
|
||||
this.setAppearance(dict);
|
||||
|
||||
@ -239,18 +262,22 @@ class Annotation {
|
||||
* @private
|
||||
*/
|
||||
_isViewable(flags) {
|
||||
return !this._hasFlag(flags, AnnotationFlag.INVISIBLE) &&
|
||||
!this._hasFlag(flags, AnnotationFlag.HIDDEN) &&
|
||||
!this._hasFlag(flags, AnnotationFlag.NOVIEW);
|
||||
return (
|
||||
!this._hasFlag(flags, AnnotationFlag.INVISIBLE) &&
|
||||
!this._hasFlag(flags, AnnotationFlag.HIDDEN) &&
|
||||
!this._hasFlag(flags, AnnotationFlag.NOVIEW)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_isPrintable(flags) {
|
||||
return this._hasFlag(flags, AnnotationFlag.PRINT) &&
|
||||
!this._hasFlag(flags, AnnotationFlag.INVISIBLE) &&
|
||||
!this._hasFlag(flags, AnnotationFlag.HIDDEN);
|
||||
return (
|
||||
this._hasFlag(flags, AnnotationFlag.PRINT) &&
|
||||
!this._hasFlag(flags, AnnotationFlag.INVISIBLE) &&
|
||||
!this._hasFlag(flags, AnnotationFlag.HIDDEN)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -283,7 +310,7 @@ class Annotation {
|
||||
* description of the annotation's contents
|
||||
*/
|
||||
setContents(contents) {
|
||||
this.contents = stringToPDFString(contents || '');
|
||||
this.contents = stringToPDFString(contents || "");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -295,8 +322,9 @@ class Annotation {
|
||||
* annotation was last modified
|
||||
*/
|
||||
setModificationDate(modificationDate) {
|
||||
this.modificationDate = isString(modificationDate) ?
|
||||
modificationDate : null;
|
||||
this.modificationDate = isString(modificationDate)
|
||||
? modificationDate
|
||||
: null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -309,7 +337,7 @@ class Annotation {
|
||||
* @see {@link shared/util.js}
|
||||
*/
|
||||
setFlags(flags) {
|
||||
this.flags = (Number.isInteger(flags) && flags > 0) ? flags : 0;
|
||||
this.flags = Number.isInteger(flags) && flags > 0 ? flags : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -392,32 +420,35 @@ class Annotation {
|
||||
* @param {Dict} borderStyle - The border style dictionary
|
||||
*/
|
||||
setBorderStyle(borderStyle) {
|
||||
if (typeof PDFJSDev === 'undefined' ||
|
||||
PDFJSDev.test('!PRODUCTION || TESTING')) {
|
||||
assert(this.rectangle, 'setRectangle must have been called previously.');
|
||||
if (
|
||||
typeof PDFJSDev === "undefined" ||
|
||||
PDFJSDev.test("!PRODUCTION || TESTING")
|
||||
) {
|
||||
assert(this.rectangle, "setRectangle must have been called previously.");
|
||||
}
|
||||
|
||||
this.borderStyle = new AnnotationBorderStyle();
|
||||
if (!isDict(borderStyle)) {
|
||||
return;
|
||||
}
|
||||
if (borderStyle.has('BS')) {
|
||||
const dict = borderStyle.get('BS');
|
||||
const dictType = dict.get('Type');
|
||||
if (borderStyle.has("BS")) {
|
||||
const dict = borderStyle.get("BS");
|
||||
const dictType = dict.get("Type");
|
||||
|
||||
if (!dictType || isName(dictType, 'Border')) {
|
||||
this.borderStyle.setWidth(dict.get('W'), this.rectangle);
|
||||
this.borderStyle.setStyle(dict.get('S'));
|
||||
this.borderStyle.setDashArray(dict.getArray('D'));
|
||||
if (!dictType || isName(dictType, "Border")) {
|
||||
this.borderStyle.setWidth(dict.get("W"), this.rectangle);
|
||||
this.borderStyle.setStyle(dict.get("S"));
|
||||
this.borderStyle.setDashArray(dict.getArray("D"));
|
||||
}
|
||||
} else if (borderStyle.has('Border')) {
|
||||
const array = borderStyle.getArray('Border');
|
||||
} else if (borderStyle.has("Border")) {
|
||||
const array = borderStyle.getArray("Border");
|
||||
if (Array.isArray(array) && array.length >= 3) {
|
||||
this.borderStyle.setHorizontalCornerRadius(array[0]);
|
||||
this.borderStyle.setVerticalCornerRadius(array[1]);
|
||||
this.borderStyle.setWidth(array[2], this.rectangle);
|
||||
|
||||
if (array.length === 4) { // Dash array available
|
||||
if (array.length === 4) {
|
||||
// Dash array available
|
||||
this.borderStyle.setDashArray(array[3]);
|
||||
}
|
||||
}
|
||||
@ -441,13 +472,13 @@ class Annotation {
|
||||
setAppearance(dict) {
|
||||
this.appearance = null;
|
||||
|
||||
const appearanceStates = dict.get('AP');
|
||||
const appearanceStates = dict.get("AP");
|
||||
if (!isDict(appearanceStates)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// In case the normal appearance is a stream, then it is used directly.
|
||||
const normalAppearanceState = appearanceStates.get('N');
|
||||
const normalAppearanceState = appearanceStates.get("N");
|
||||
if (isStream(normalAppearanceState)) {
|
||||
this.appearance = normalAppearanceState;
|
||||
return;
|
||||
@ -458,7 +489,7 @@ class Annotation {
|
||||
|
||||
// In case the normal appearance is a dictionary, the `AS` entry provides
|
||||
// the key of the stream in this dictionary.
|
||||
const as = dict.get('AS');
|
||||
const as = dict.get("AS");
|
||||
if (!isName(as) || !normalAppearanceState.has(as.name)) {
|
||||
return;
|
||||
}
|
||||
@ -466,7 +497,7 @@ class Annotation {
|
||||
}
|
||||
|
||||
loadResources(keys) {
|
||||
return this.appearance.dict.getAsync('Resources').then((resources) => {
|
||||
return this.appearance.dict.getAsync("Resources").then(resources => {
|
||||
if (!resources) {
|
||||
return undefined;
|
||||
}
|
||||
@ -486,30 +517,32 @@ class Annotation {
|
||||
const data = this.data;
|
||||
const appearanceDict = this.appearance.dict;
|
||||
const resourcesPromise = this.loadResources([
|
||||
'ExtGState',
|
||||
'ColorSpace',
|
||||
'Pattern',
|
||||
'Shading',
|
||||
'XObject',
|
||||
'Font',
|
||||
"ExtGState",
|
||||
"ColorSpace",
|
||||
"Pattern",
|
||||
"Shading",
|
||||
"XObject",
|
||||
"Font",
|
||||
]);
|
||||
const bbox = appearanceDict.getArray('BBox') || [0, 0, 1, 1];
|
||||
const matrix = appearanceDict.getArray('Matrix') || [1, 0, 0, 1, 0, 0];
|
||||
const bbox = appearanceDict.getArray("BBox") || [0, 0, 1, 1];
|
||||
const matrix = appearanceDict.getArray("Matrix") || [1, 0, 0, 1, 0, 0];
|
||||
const transform = getTransformMatrix(data.rect, bbox, matrix);
|
||||
|
||||
return resourcesPromise.then((resources) => {
|
||||
return resourcesPromise.then(resources => {
|
||||
const opList = new OperatorList();
|
||||
opList.addOp(OPS.beginAnnotation, [data.rect, transform, matrix]);
|
||||
return evaluator.getOperatorList({
|
||||
stream: this.appearance,
|
||||
task,
|
||||
resources,
|
||||
operatorList: opList,
|
||||
}).then(() => {
|
||||
opList.addOp(OPS.endAnnotation, []);
|
||||
this.appearance.reset();
|
||||
return opList;
|
||||
});
|
||||
return evaluator
|
||||
.getOperatorList({
|
||||
stream: this.appearance,
|
||||
task,
|
||||
resources,
|
||||
operatorList: opList,
|
||||
})
|
||||
.then(() => {
|
||||
opList.addOp(OPS.endAnnotation, []);
|
||||
this.appearance.reset();
|
||||
return opList;
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -535,10 +568,14 @@ class AnnotationBorderStyle {
|
||||
* @param {Array} rect - The annotation `Rect` entry.
|
||||
*/
|
||||
setWidth(width, rect = [0, 0, 0, 0]) {
|
||||
if (typeof PDFJSDev === 'undefined' ||
|
||||
PDFJSDev.test('!PRODUCTION || TESTING')) {
|
||||
assert(Array.isArray(rect) && rect.length === 4,
|
||||
'A valid `rect` parameter must be provided.');
|
||||
if (
|
||||
typeof PDFJSDev === "undefined" ||
|
||||
PDFJSDev.test("!PRODUCTION || TESTING")
|
||||
) {
|
||||
assert(
|
||||
Array.isArray(rect) && rect.length === 4,
|
||||
"A valid `rect` parameter must be provided."
|
||||
);
|
||||
}
|
||||
|
||||
// Some corrupt PDF generators may provide the width as a `Name`,
|
||||
@ -555,8 +592,11 @@ class AnnotationBorderStyle {
|
||||
// Ignore large `width`s, since they lead to the Annotation overflowing
|
||||
// the size set by the `Rect` entry thus causing the `annotationLayer`
|
||||
// to render it over the surrounding document (fixes bug1552113.pdf).
|
||||
if ((maxWidth > 0 && maxHeight > 0) &&
|
||||
(width > maxWidth || width > maxHeight)) {
|
||||
if (
|
||||
maxWidth > 0 &&
|
||||
maxHeight > 0 &&
|
||||
(width > maxWidth || width > maxHeight)
|
||||
) {
|
||||
warn(`AnnotationBorderStyle.setWidth - ignoring width: ${width}`);
|
||||
width = 1;
|
||||
}
|
||||
@ -578,23 +618,23 @@ class AnnotationBorderStyle {
|
||||
return;
|
||||
}
|
||||
switch (style.name) {
|
||||
case 'S':
|
||||
case "S":
|
||||
this.style = AnnotationBorderStyleType.SOLID;
|
||||
break;
|
||||
|
||||
case 'D':
|
||||
case "D":
|
||||
this.style = AnnotationBorderStyleType.DASHED;
|
||||
break;
|
||||
|
||||
case 'B':
|
||||
case "B":
|
||||
this.style = AnnotationBorderStyleType.BEVELED;
|
||||
break;
|
||||
|
||||
case 'I':
|
||||
case "I":
|
||||
this.style = AnnotationBorderStyleType.INSET;
|
||||
break;
|
||||
|
||||
case 'U':
|
||||
case "U":
|
||||
this.style = AnnotationBorderStyleType.UNDERLINE;
|
||||
break;
|
||||
|
||||
@ -620,7 +660,7 @@ class AnnotationBorderStyle {
|
||||
let isValid = true;
|
||||
let allZeros = true;
|
||||
for (const element of dashArray) {
|
||||
const validNumber = (+element >= 0);
|
||||
const validNumber = +element >= 0;
|
||||
if (!validNumber) {
|
||||
isValid = false;
|
||||
break;
|
||||
@ -671,56 +711,56 @@ class MarkupAnnotation extends Annotation {
|
||||
|
||||
const dict = parameters.dict;
|
||||
|
||||
if (dict.has('IRT')) {
|
||||
const rawIRT = dict.getRaw('IRT');
|
||||
if (dict.has("IRT")) {
|
||||
const rawIRT = dict.getRaw("IRT");
|
||||
this.data.inReplyTo = isRef(rawIRT) ? rawIRT.toString() : null;
|
||||
|
||||
const rt = dict.get('RT');
|
||||
const rt = dict.get("RT");
|
||||
this.data.replyType = isName(rt) ? rt.name : AnnotationReplyType.REPLY;
|
||||
}
|
||||
|
||||
if (this.data.replyType === AnnotationReplyType.GROUP) {
|
||||
// Subordinate annotations in a group should inherit
|
||||
// the group attributes from the primary annotation.
|
||||
const parent = dict.get('IRT');
|
||||
const parent = dict.get("IRT");
|
||||
|
||||
this.data.title = stringToPDFString(parent.get('T') || '');
|
||||
this.data.title = stringToPDFString(parent.get("T") || "");
|
||||
|
||||
this.setContents(parent.get('Contents'));
|
||||
this.setContents(parent.get("Contents"));
|
||||
this.data.contents = this.contents;
|
||||
|
||||
if (!parent.has('CreationDate')) {
|
||||
if (!parent.has("CreationDate")) {
|
||||
this.data.creationDate = null;
|
||||
} else {
|
||||
this.setCreationDate(parent.get('CreationDate'));
|
||||
this.setCreationDate(parent.get("CreationDate"));
|
||||
this.data.creationDate = this.creationDate;
|
||||
}
|
||||
|
||||
if (!parent.has('M')) {
|
||||
if (!parent.has("M")) {
|
||||
this.data.modificationDate = null;
|
||||
} else {
|
||||
this.setModificationDate(parent.get('M'));
|
||||
this.setModificationDate(parent.get("M"));
|
||||
this.data.modificationDate = this.modificationDate;
|
||||
}
|
||||
|
||||
this.data.hasPopup = parent.has('Popup');
|
||||
this.data.hasPopup = parent.has("Popup");
|
||||
|
||||
if (!parent.has('C')) {
|
||||
if (!parent.has("C")) {
|
||||
// Fall back to the default background color.
|
||||
this.data.color = null;
|
||||
} else {
|
||||
this.setColor(parent.getArray('C'));
|
||||
this.setColor(parent.getArray("C"));
|
||||
this.data.color = this.color;
|
||||
}
|
||||
} else {
|
||||
this.data.title = stringToPDFString(dict.get('T') || '');
|
||||
this.data.title = stringToPDFString(dict.get("T") || "");
|
||||
|
||||
this.setCreationDate(dict.get('CreationDate'));
|
||||
this.setCreationDate(dict.get("CreationDate"));
|
||||
this.data.creationDate = this.creationDate;
|
||||
|
||||
this.data.hasPopup = dict.has('Popup');
|
||||
this.data.hasPopup = dict.has("Popup");
|
||||
|
||||
if (!dict.has('C')) {
|
||||
if (!dict.has("C")) {
|
||||
// Fall back to the default background color.
|
||||
this.data.color = null;
|
||||
}
|
||||
@ -749,16 +789,19 @@ class WidgetAnnotation extends Annotation {
|
||||
|
||||
data.annotationType = AnnotationType.WIDGET;
|
||||
data.fieldName = this._constructFieldName(dict);
|
||||
data.fieldValue = getInheritableProperty({ dict, key: 'V',
|
||||
getArray: true, });
|
||||
data.alternativeText = stringToPDFString(dict.get('TU') || '');
|
||||
data.defaultAppearance = getInheritableProperty({ dict, key: 'DA', }) || '';
|
||||
const fieldType = getInheritableProperty({ dict, key: 'FT', });
|
||||
data.fieldValue = getInheritableProperty({
|
||||
dict,
|
||||
key: "V",
|
||||
getArray: true,
|
||||
});
|
||||
data.alternativeText = stringToPDFString(dict.get("TU") || "");
|
||||
data.defaultAppearance = getInheritableProperty({ dict, key: "DA" }) || "";
|
||||
const fieldType = getInheritableProperty({ dict, key: "FT" });
|
||||
data.fieldType = isName(fieldType) ? fieldType.name : null;
|
||||
this.fieldResources = getInheritableProperty({ dict, key: 'DR', }) ||
|
||||
Dict.empty;
|
||||
this.fieldResources =
|
||||
getInheritableProperty({ dict, key: "DR" }) || Dict.empty;
|
||||
|
||||
data.fieldFlags = getInheritableProperty({ dict, key: 'Ff', });
|
||||
data.fieldFlags = getInheritableProperty({ dict, key: "Ff" });
|
||||
if (!Number.isInteger(data.fieldFlags) || data.fieldFlags < 0) {
|
||||
data.fieldFlags = 0;
|
||||
}
|
||||
@ -768,7 +811,7 @@ class WidgetAnnotation extends Annotation {
|
||||
// Hide signatures because we cannot validate them, and unset the fieldValue
|
||||
// since it's (most likely) a `Dict` which is non-serializable and will thus
|
||||
// cause errors when sending annotations to the main-thread (issue 10347).
|
||||
if (data.fieldType === 'Sig') {
|
||||
if (data.fieldType === "Sig") {
|
||||
data.fieldValue = null;
|
||||
this.setFlags(AnnotationFlag.HIDDEN);
|
||||
}
|
||||
@ -786,26 +829,26 @@ class WidgetAnnotation extends Annotation {
|
||||
_constructFieldName(dict) {
|
||||
// Both the `Parent` and `T` fields are optional. While at least one of
|
||||
// them should be provided, bad PDF generators may fail to do so.
|
||||
if (!dict.has('T') && !dict.has('Parent')) {
|
||||
warn('Unknown field name, falling back to empty field name.');
|
||||
return '';
|
||||
if (!dict.has("T") && !dict.has("Parent")) {
|
||||
warn("Unknown field name, falling back to empty field name.");
|
||||
return "";
|
||||
}
|
||||
|
||||
// If no parent exists, the partial and fully qualified names are equal.
|
||||
if (!dict.has('Parent')) {
|
||||
return stringToPDFString(dict.get('T'));
|
||||
if (!dict.has("Parent")) {
|
||||
return stringToPDFString(dict.get("T"));
|
||||
}
|
||||
|
||||
// Form the fully qualified field name by appending the partial name to
|
||||
// the parent's fully qualified name, separated by a period.
|
||||
const fieldName = [];
|
||||
if (dict.has('T')) {
|
||||
fieldName.unshift(stringToPDFString(dict.get('T')));
|
||||
if (dict.has("T")) {
|
||||
fieldName.unshift(stringToPDFString(dict.get("T")));
|
||||
}
|
||||
|
||||
let loopDict = dict;
|
||||
while (loopDict.has('Parent')) {
|
||||
loopDict = loopDict.get('Parent');
|
||||
while (loopDict.has("Parent")) {
|
||||
loopDict = loopDict.get("Parent");
|
||||
if (!isDict(loopDict)) {
|
||||
// Even though it is not allowed according to the PDF specification,
|
||||
// bad PDF generators may provide a `Parent` entry that is not a
|
||||
@ -813,11 +856,11 @@ class WidgetAnnotation extends Annotation {
|
||||
break;
|
||||
}
|
||||
|
||||
if (loopDict.has('T')) {
|
||||
fieldName.unshift(stringToPDFString(loopDict.get('T')));
|
||||
if (loopDict.has("T")) {
|
||||
fieldName.unshift(stringToPDFString(loopDict.get("T")));
|
||||
}
|
||||
}
|
||||
return fieldName.join('.');
|
||||
return fieldName.join(".");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -851,17 +894,17 @@ class TextWidgetAnnotation extends WidgetAnnotation {
|
||||
const dict = params.dict;
|
||||
|
||||
// The field value is always a string.
|
||||
this.data.fieldValue = stringToPDFString(this.data.fieldValue || '');
|
||||
this.data.fieldValue = stringToPDFString(this.data.fieldValue || "");
|
||||
|
||||
// Determine the alignment of text in the field.
|
||||
let alignment = getInheritableProperty({ dict, key: 'Q', });
|
||||
let alignment = getInheritableProperty({ dict, key: "Q" });
|
||||
if (!Number.isInteger(alignment) || alignment < 0 || alignment > 2) {
|
||||
alignment = null;
|
||||
}
|
||||
this.data.textAlignment = alignment;
|
||||
|
||||
// Determine the maximum length of text in the field.
|
||||
let maximumLength = getInheritableProperty({ dict, key: 'MaxLen', });
|
||||
let maximumLength = getInheritableProperty({ dict, key: "MaxLen" });
|
||||
if (!Number.isInteger(maximumLength) || maximumLength < 0) {
|
||||
maximumLength = null;
|
||||
}
|
||||
@ -869,11 +912,12 @@ class TextWidgetAnnotation extends WidgetAnnotation {
|
||||
|
||||
// Process field flags for the display layer.
|
||||
this.data.multiLine = this.hasFieldFlag(AnnotationFieldFlag.MULTILINE);
|
||||
this.data.comb = this.hasFieldFlag(AnnotationFieldFlag.COMB) &&
|
||||
!this.hasFieldFlag(AnnotationFieldFlag.MULTILINE) &&
|
||||
!this.hasFieldFlag(AnnotationFieldFlag.PASSWORD) &&
|
||||
!this.hasFieldFlag(AnnotationFieldFlag.FILESELECT) &&
|
||||
this.data.maxLen !== null;
|
||||
this.data.comb =
|
||||
this.hasFieldFlag(AnnotationFieldFlag.COMB) &&
|
||||
!this.hasFieldFlag(AnnotationFieldFlag.MULTILINE) &&
|
||||
!this.hasFieldFlag(AnnotationFieldFlag.PASSWORD) &&
|
||||
!this.hasFieldFlag(AnnotationFieldFlag.FILESELECT) &&
|
||||
this.data.maxLen !== null;
|
||||
}
|
||||
|
||||
getOperatorList(evaluator, task, renderForms) {
|
||||
@ -890,14 +934,16 @@ class TextWidgetAnnotation extends WidgetAnnotation {
|
||||
}
|
||||
|
||||
const stream = new Stream(stringToBytes(this.data.defaultAppearance));
|
||||
return evaluator.getOperatorList({
|
||||
stream,
|
||||
task,
|
||||
resources: this.fieldResources,
|
||||
operatorList,
|
||||
}).then(function () {
|
||||
return operatorList;
|
||||
});
|
||||
return evaluator
|
||||
.getOperatorList({
|
||||
stream,
|
||||
task,
|
||||
resources: this.fieldResources,
|
||||
operatorList,
|
||||
})
|
||||
.then(function() {
|
||||
return operatorList;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -905,10 +951,12 @@ class ButtonWidgetAnnotation extends WidgetAnnotation {
|
||||
constructor(params) {
|
||||
super(params);
|
||||
|
||||
this.data.checkBox = !this.hasFieldFlag(AnnotationFieldFlag.RADIO) &&
|
||||
!this.hasFieldFlag(AnnotationFieldFlag.PUSHBUTTON);
|
||||
this.data.radioButton = this.hasFieldFlag(AnnotationFieldFlag.RADIO) &&
|
||||
!this.hasFieldFlag(AnnotationFieldFlag.PUSHBUTTON);
|
||||
this.data.checkBox =
|
||||
!this.hasFieldFlag(AnnotationFieldFlag.RADIO) &&
|
||||
!this.hasFieldFlag(AnnotationFieldFlag.PUSHBUTTON);
|
||||
this.data.radioButton =
|
||||
this.hasFieldFlag(AnnotationFieldFlag.RADIO) &&
|
||||
!this.hasFieldFlag(AnnotationFieldFlag.PUSHBUTTON);
|
||||
this.data.pushButton = this.hasFieldFlag(AnnotationFieldFlag.PUSHBUTTON);
|
||||
|
||||
if (this.data.checkBox) {
|
||||
@ -918,7 +966,7 @@ class ButtonWidgetAnnotation extends WidgetAnnotation {
|
||||
} else if (this.data.pushButton) {
|
||||
this._processPushButton(params);
|
||||
} else {
|
||||
warn('Invalid field flags for button widget annotation');
|
||||
warn("Invalid field flags for button widget annotation");
|
||||
}
|
||||
}
|
||||
|
||||
@ -927,12 +975,12 @@ class ButtonWidgetAnnotation extends WidgetAnnotation {
|
||||
this.data.fieldValue = this.data.fieldValue.name;
|
||||
}
|
||||
|
||||
const customAppearance = params.dict.get('AP');
|
||||
const customAppearance = params.dict.get("AP");
|
||||
if (!isDict(customAppearance)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const exportValueOptionsDict = customAppearance.get('D');
|
||||
const exportValueOptionsDict = customAppearance.get("D");
|
||||
if (!isDict(exportValueOptionsDict)) {
|
||||
return;
|
||||
}
|
||||
@ -943,8 +991,8 @@ class ButtonWidgetAnnotation extends WidgetAnnotation {
|
||||
return;
|
||||
}
|
||||
|
||||
this.data.exportValue = exportValues[0] === 'Off' ?
|
||||
exportValues[1] : exportValues[0];
|
||||
this.data.exportValue =
|
||||
exportValues[0] === "Off" ? exportValues[1] : exportValues[0];
|
||||
}
|
||||
|
||||
_processRadioButton(params) {
|
||||
@ -952,25 +1000,25 @@ class ButtonWidgetAnnotation extends WidgetAnnotation {
|
||||
|
||||
// The parent field's `V` entry holds a `Name` object with the appearance
|
||||
// state of whichever child field is currently in the "on" state.
|
||||
const fieldParent = params.dict.get('Parent');
|
||||
if (isDict(fieldParent) && fieldParent.has('V')) {
|
||||
const fieldParentValue = fieldParent.get('V');
|
||||
const fieldParent = params.dict.get("Parent");
|
||||
if (isDict(fieldParent) && fieldParent.has("V")) {
|
||||
const fieldParentValue = fieldParent.get("V");
|
||||
if (isName(fieldParentValue)) {
|
||||
this.data.fieldValue = fieldParentValue.name;
|
||||
}
|
||||
}
|
||||
|
||||
// The button's value corresponds to its appearance state.
|
||||
const appearanceStates = params.dict.get('AP');
|
||||
const appearanceStates = params.dict.get("AP");
|
||||
if (!isDict(appearanceStates)) {
|
||||
return;
|
||||
}
|
||||
const normalAppearanceState = appearanceStates.get('N');
|
||||
const normalAppearanceState = appearanceStates.get("N");
|
||||
if (!isDict(normalAppearanceState)) {
|
||||
return;
|
||||
}
|
||||
for (const key of normalAppearanceState.getKeys()) {
|
||||
if (key !== 'Off') {
|
||||
if (key !== "Off") {
|
||||
this.data.buttonValue = key;
|
||||
break;
|
||||
}
|
||||
@ -978,8 +1026,8 @@ class ButtonWidgetAnnotation extends WidgetAnnotation {
|
||||
}
|
||||
|
||||
_processPushButton(params) {
|
||||
if (!params.dict.has('A')) {
|
||||
warn('Push buttons without action dictionaries are not supported');
|
||||
if (!params.dict.has("A")) {
|
||||
warn("Push buttons without action dictionaries are not supported");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1006,7 +1054,7 @@ class ChoiceWidgetAnnotation extends WidgetAnnotation {
|
||||
// inherit the options from a parent annotation (issue 8094).
|
||||
this.data.options = [];
|
||||
|
||||
const options = getInheritableProperty({ dict: params.dict, key: 'Opt', });
|
||||
const options = getInheritableProperty({ dict: params.dict, key: "Opt" });
|
||||
if (Array.isArray(options)) {
|
||||
const xref = params.xref;
|
||||
for (let i = 0, ii = options.length; i < ii; i++) {
|
||||
@ -1015,8 +1063,9 @@ class ChoiceWidgetAnnotation extends WidgetAnnotation {
|
||||
|
||||
this.data.options[i] = {
|
||||
exportValue: isOptionArray ? xref.fetchIfRef(option[0]) : option,
|
||||
displayValue: stringToPDFString(isOptionArray ?
|
||||
xref.fetchIfRef(option[1]) : option),
|
||||
displayValue: stringToPDFString(
|
||||
isOptionArray ? xref.fetchIfRef(option[1]) : option
|
||||
),
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -1044,17 +1093,16 @@ class TextAnnotation extends MarkupAnnotation {
|
||||
this.data.annotationType = AnnotationType.TEXT;
|
||||
|
||||
if (this.data.hasAppearance) {
|
||||
this.data.name = 'NoIcon';
|
||||
this.data.name = "NoIcon";
|
||||
} else {
|
||||
this.data.rect[1] = this.data.rect[3] - DEFAULT_ICON_SIZE;
|
||||
this.data.rect[2] = this.data.rect[0] + DEFAULT_ICON_SIZE;
|
||||
this.data.name = dict.has('Name') ?
|
||||
dict.get('Name').name : 'Note';
|
||||
this.data.name = dict.has("Name") ? dict.get("Name").name : "Note";
|
||||
}
|
||||
|
||||
if (dict.has('State')) {
|
||||
this.data.state = dict.get('State') || null;
|
||||
this.data.stateModel = dict.get('StateModel') || null;
|
||||
if (dict.has("State")) {
|
||||
this.data.state = dict.get("State") || null;
|
||||
this.data.stateModel = dict.get("StateModel") || null;
|
||||
} else {
|
||||
this.data.state = null;
|
||||
this.data.stateModel = null;
|
||||
@ -1087,36 +1135,36 @@ class PopupAnnotation extends Annotation {
|
||||
|
||||
this.data.annotationType = AnnotationType.POPUP;
|
||||
|
||||
let parentItem = parameters.dict.get('Parent');
|
||||
let parentItem = parameters.dict.get("Parent");
|
||||
if (!parentItem) {
|
||||
warn('Popup annotation has a missing or invalid parent annotation.');
|
||||
warn("Popup annotation has a missing or invalid parent annotation.");
|
||||
return;
|
||||
}
|
||||
|
||||
const parentSubtype = parentItem.get('Subtype');
|
||||
const parentSubtype = parentItem.get("Subtype");
|
||||
this.data.parentType = isName(parentSubtype) ? parentSubtype.name : null;
|
||||
const rawParent = parameters.dict.getRaw('Parent');
|
||||
const rawParent = parameters.dict.getRaw("Parent");
|
||||
this.data.parentId = isRef(rawParent) ? rawParent.toString() : null;
|
||||
|
||||
const rt = parentItem.get('RT');
|
||||
const rt = parentItem.get("RT");
|
||||
if (isName(rt, AnnotationReplyType.GROUP)) {
|
||||
// Subordinate annotations in a group should inherit
|
||||
// the group attributes from the primary annotation.
|
||||
parentItem = parentItem.get('IRT');
|
||||
parentItem = parentItem.get("IRT");
|
||||
}
|
||||
|
||||
if (!parentItem.has('M')) {
|
||||
if (!parentItem.has("M")) {
|
||||
this.data.modificationDate = null;
|
||||
} else {
|
||||
this.setModificationDate(parentItem.get('M'));
|
||||
this.setModificationDate(parentItem.get("M"));
|
||||
this.data.modificationDate = this.modificationDate;
|
||||
}
|
||||
|
||||
if (!parentItem.has('C')) {
|
||||
if (!parentItem.has("C")) {
|
||||
// Fall back to the default background color.
|
||||
this.data.color = null;
|
||||
} else {
|
||||
this.setColor(parentItem.getArray('C'));
|
||||
this.setColor(parentItem.getArray("C"));
|
||||
this.data.color = this.color;
|
||||
}
|
||||
|
||||
@ -1124,14 +1172,14 @@ class PopupAnnotation extends Annotation {
|
||||
// that is most likely a bug. Fallback to inherit the flags from the parent
|
||||
// annotation (this is consistent with the behaviour in Adobe Reader).
|
||||
if (!this.viewable) {
|
||||
const parentFlags = parentItem.get('F');
|
||||
const parentFlags = parentItem.get("F");
|
||||
if (this._isViewable(parentFlags)) {
|
||||
this.setFlags(parentFlags);
|
||||
}
|
||||
}
|
||||
|
||||
this.data.title = stringToPDFString(parentItem.get('T') || '');
|
||||
this.data.contents = stringToPDFString(parentItem.get('Contents') || '');
|
||||
this.data.title = stringToPDFString(parentItem.get("T") || "");
|
||||
this.data.contents = stringToPDFString(parentItem.get("Contents") || "");
|
||||
}
|
||||
}
|
||||
|
||||
@ -1149,8 +1197,9 @@ class LineAnnotation extends MarkupAnnotation {
|
||||
|
||||
this.data.annotationType = AnnotationType.LINE;
|
||||
|
||||
this.data.lineCoordinates =
|
||||
Util.normalizeRect(parameters.dict.getArray('L'));
|
||||
this.data.lineCoordinates = Util.normalizeRect(
|
||||
parameters.dict.getArray("L")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1179,7 +1228,7 @@ class PolylineAnnotation extends MarkupAnnotation {
|
||||
// The vertices array is an array of numbers representing the alternating
|
||||
// horizontal and vertical coordinates, respectively, of each vertex.
|
||||
// Convert this to an array of objects with x and y coordinates.
|
||||
const rawVertices = parameters.dict.getArray('Vertices');
|
||||
const rawVertices = parameters.dict.getArray("Vertices");
|
||||
this.data.vertices = [];
|
||||
for (let i = 0, ii = rawVertices.length; i < ii; i += 2) {
|
||||
this.data.vertices.push({
|
||||
@ -1214,7 +1263,7 @@ class InkAnnotation extends MarkupAnnotation {
|
||||
this.data.annotationType = AnnotationType.INK;
|
||||
|
||||
const xref = parameters.xref;
|
||||
const originalInkLists = parameters.dict.getArray('InkList');
|
||||
const originalInkLists = parameters.dict.getArray("InkList");
|
||||
this.data.inkLists = [];
|
||||
for (let i = 0, ii = originalInkLists.length; i < ii; ++i) {
|
||||
// The raw ink lists array contains arrays of numbers representing
|
||||
@ -1296,7 +1345,7 @@ class FileAttachmentAnnotation extends MarkupAnnotation {
|
||||
constructor(parameters) {
|
||||
super(parameters);
|
||||
|
||||
const file = new FileSpec(parameters.dict.get('FS'), parameters.xref);
|
||||
const file = new FileSpec(parameters.dict.get("FS"), parameters.xref);
|
||||
|
||||
this.data.annotationType = AnnotationType.FILEATTACHMENT;
|
||||
this.data.file = file.serializable;
|
||||
|
@ -16,53 +16,53 @@
|
||||
|
||||
// Table C-2
|
||||
const QeTable = [
|
||||
{ qe: 0x5601, nmps: 1, nlps: 1, switchFlag: 1, },
|
||||
{ qe: 0x3401, nmps: 2, nlps: 6, switchFlag: 0, },
|
||||
{ qe: 0x1801, nmps: 3, nlps: 9, switchFlag: 0, },
|
||||
{ qe: 0x0AC1, nmps: 4, nlps: 12, switchFlag: 0, },
|
||||
{ qe: 0x0521, nmps: 5, nlps: 29, switchFlag: 0, },
|
||||
{ qe: 0x0221, nmps: 38, nlps: 33, switchFlag: 0, },
|
||||
{ qe: 0x5601, nmps: 7, nlps: 6, switchFlag: 1, },
|
||||
{ qe: 0x5401, nmps: 8, nlps: 14, switchFlag: 0, },
|
||||
{ qe: 0x4801, nmps: 9, nlps: 14, switchFlag: 0, },
|
||||
{ qe: 0x3801, nmps: 10, nlps: 14, switchFlag: 0, },
|
||||
{ qe: 0x3001, nmps: 11, nlps: 17, switchFlag: 0, },
|
||||
{ qe: 0x2401, nmps: 12, nlps: 18, switchFlag: 0, },
|
||||
{ qe: 0x1C01, nmps: 13, nlps: 20, switchFlag: 0, },
|
||||
{ qe: 0x1601, nmps: 29, nlps: 21, switchFlag: 0, },
|
||||
{ qe: 0x5601, nmps: 15, nlps: 14, switchFlag: 1, },
|
||||
{ qe: 0x5401, nmps: 16, nlps: 14, switchFlag: 0, },
|
||||
{ qe: 0x5101, nmps: 17, nlps: 15, switchFlag: 0, },
|
||||
{ qe: 0x4801, nmps: 18, nlps: 16, switchFlag: 0, },
|
||||
{ qe: 0x3801, nmps: 19, nlps: 17, switchFlag: 0, },
|
||||
{ qe: 0x3401, nmps: 20, nlps: 18, switchFlag: 0, },
|
||||
{ qe: 0x3001, nmps: 21, nlps: 19, switchFlag: 0, },
|
||||
{ qe: 0x2801, nmps: 22, nlps: 19, switchFlag: 0, },
|
||||
{ qe: 0x2401, nmps: 23, nlps: 20, switchFlag: 0, },
|
||||
{ qe: 0x2201, nmps: 24, nlps: 21, switchFlag: 0, },
|
||||
{ qe: 0x1C01, nmps: 25, nlps: 22, switchFlag: 0, },
|
||||
{ qe: 0x1801, nmps: 26, nlps: 23, switchFlag: 0, },
|
||||
{ qe: 0x1601, nmps: 27, nlps: 24, switchFlag: 0, },
|
||||
{ qe: 0x1401, nmps: 28, nlps: 25, switchFlag: 0, },
|
||||
{ qe: 0x1201, nmps: 29, nlps: 26, switchFlag: 0, },
|
||||
{ qe: 0x1101, nmps: 30, nlps: 27, switchFlag: 0, },
|
||||
{ qe: 0x0AC1, nmps: 31, nlps: 28, switchFlag: 0, },
|
||||
{ qe: 0x09C1, nmps: 32, nlps: 29, switchFlag: 0, },
|
||||
{ qe: 0x08A1, nmps: 33, nlps: 30, switchFlag: 0, },
|
||||
{ qe: 0x0521, nmps: 34, nlps: 31, switchFlag: 0, },
|
||||
{ qe: 0x0441, nmps: 35, nlps: 32, switchFlag: 0, },
|
||||
{ qe: 0x02A1, nmps: 36, nlps: 33, switchFlag: 0, },
|
||||
{ qe: 0x0221, nmps: 37, nlps: 34, switchFlag: 0, },
|
||||
{ qe: 0x0141, nmps: 38, nlps: 35, switchFlag: 0, },
|
||||
{ qe: 0x0111, nmps: 39, nlps: 36, switchFlag: 0, },
|
||||
{ qe: 0x0085, nmps: 40, nlps: 37, switchFlag: 0, },
|
||||
{ qe: 0x0049, nmps: 41, nlps: 38, switchFlag: 0, },
|
||||
{ qe: 0x0025, nmps: 42, nlps: 39, switchFlag: 0, },
|
||||
{ qe: 0x0015, nmps: 43, nlps: 40, switchFlag: 0, },
|
||||
{ qe: 0x0009, nmps: 44, nlps: 41, switchFlag: 0, },
|
||||
{ qe: 0x0005, nmps: 45, nlps: 42, switchFlag: 0, },
|
||||
{ qe: 0x0001, nmps: 45, nlps: 43, switchFlag: 0, },
|
||||
{ qe: 0x5601, nmps: 46, nlps: 46, switchFlag: 0, },
|
||||
{ qe: 0x5601, nmps: 1, nlps: 1, switchFlag: 1 },
|
||||
{ qe: 0x3401, nmps: 2, nlps: 6, switchFlag: 0 },
|
||||
{ qe: 0x1801, nmps: 3, nlps: 9, switchFlag: 0 },
|
||||
{ qe: 0x0ac1, nmps: 4, nlps: 12, switchFlag: 0 },
|
||||
{ qe: 0x0521, nmps: 5, nlps: 29, switchFlag: 0 },
|
||||
{ qe: 0x0221, nmps: 38, nlps: 33, switchFlag: 0 },
|
||||
{ qe: 0x5601, nmps: 7, nlps: 6, switchFlag: 1 },
|
||||
{ qe: 0x5401, nmps: 8, nlps: 14, switchFlag: 0 },
|
||||
{ qe: 0x4801, nmps: 9, nlps: 14, switchFlag: 0 },
|
||||
{ qe: 0x3801, nmps: 10, nlps: 14, switchFlag: 0 },
|
||||
{ qe: 0x3001, nmps: 11, nlps: 17, switchFlag: 0 },
|
||||
{ qe: 0x2401, nmps: 12, nlps: 18, switchFlag: 0 },
|
||||
{ qe: 0x1c01, nmps: 13, nlps: 20, switchFlag: 0 },
|
||||
{ qe: 0x1601, nmps: 29, nlps: 21, switchFlag: 0 },
|
||||
{ qe: 0x5601, nmps: 15, nlps: 14, switchFlag: 1 },
|
||||
{ qe: 0x5401, nmps: 16, nlps: 14, switchFlag: 0 },
|
||||
{ qe: 0x5101, nmps: 17, nlps: 15, switchFlag: 0 },
|
||||
{ qe: 0x4801, nmps: 18, nlps: 16, switchFlag: 0 },
|
||||
{ qe: 0x3801, nmps: 19, nlps: 17, switchFlag: 0 },
|
||||
{ qe: 0x3401, nmps: 20, nlps: 18, switchFlag: 0 },
|
||||
{ qe: 0x3001, nmps: 21, nlps: 19, switchFlag: 0 },
|
||||
{ qe: 0x2801, nmps: 22, nlps: 19, switchFlag: 0 },
|
||||
{ qe: 0x2401, nmps: 23, nlps: 20, switchFlag: 0 },
|
||||
{ qe: 0x2201, nmps: 24, nlps: 21, switchFlag: 0 },
|
||||
{ qe: 0x1c01, nmps: 25, nlps: 22, switchFlag: 0 },
|
||||
{ qe: 0x1801, nmps: 26, nlps: 23, switchFlag: 0 },
|
||||
{ qe: 0x1601, nmps: 27, nlps: 24, switchFlag: 0 },
|
||||
{ qe: 0x1401, nmps: 28, nlps: 25, switchFlag: 0 },
|
||||
{ qe: 0x1201, nmps: 29, nlps: 26, switchFlag: 0 },
|
||||
{ qe: 0x1101, nmps: 30, nlps: 27, switchFlag: 0 },
|
||||
{ qe: 0x0ac1, nmps: 31, nlps: 28, switchFlag: 0 },
|
||||
{ qe: 0x09c1, nmps: 32, nlps: 29, switchFlag: 0 },
|
||||
{ qe: 0x08a1, nmps: 33, nlps: 30, switchFlag: 0 },
|
||||
{ qe: 0x0521, nmps: 34, nlps: 31, switchFlag: 0 },
|
||||
{ qe: 0x0441, nmps: 35, nlps: 32, switchFlag: 0 },
|
||||
{ qe: 0x02a1, nmps: 36, nlps: 33, switchFlag: 0 },
|
||||
{ qe: 0x0221, nmps: 37, nlps: 34, switchFlag: 0 },
|
||||
{ qe: 0x0141, nmps: 38, nlps: 35, switchFlag: 0 },
|
||||
{ qe: 0x0111, nmps: 39, nlps: 36, switchFlag: 0 },
|
||||
{ qe: 0x0085, nmps: 40, nlps: 37, switchFlag: 0 },
|
||||
{ qe: 0x0049, nmps: 41, nlps: 38, switchFlag: 0 },
|
||||
{ qe: 0x0025, nmps: 42, nlps: 39, switchFlag: 0 },
|
||||
{ qe: 0x0015, nmps: 43, nlps: 40, switchFlag: 0 },
|
||||
{ qe: 0x0009, nmps: 44, nlps: 41, switchFlag: 0 },
|
||||
{ qe: 0x0005, nmps: 45, nlps: 42, switchFlag: 0 },
|
||||
{ qe: 0x0001, nmps: 45, nlps: 43, switchFlag: 0 },
|
||||
{ qe: 0x5601, nmps: 46, nlps: 46, switchFlag: 0 },
|
||||
];
|
||||
|
||||
/**
|
||||
@ -86,8 +86,8 @@ class ArithmeticDecoder {
|
||||
|
||||
this.byteIn();
|
||||
|
||||
this.chigh = ((this.chigh << 7) & 0xFFFF) | ((this.clow >> 9) & 0x7F);
|
||||
this.clow = (this.clow << 7) & 0xFFFF;
|
||||
this.chigh = ((this.chigh << 7) & 0xffff) | ((this.clow >> 9) & 0x7f);
|
||||
this.clow = (this.clow << 7) & 0xffff;
|
||||
this.ct -= 7;
|
||||
this.a = 0x8000;
|
||||
}
|
||||
@ -97,25 +97,25 @@ class ArithmeticDecoder {
|
||||
const data = this.data;
|
||||
let bp = this.bp;
|
||||
|
||||
if (data[bp] === 0xFF) {
|
||||
if (data[bp + 1] > 0x8F) {
|
||||
this.clow += 0xFF00;
|
||||
if (data[bp] === 0xff) {
|
||||
if (data[bp + 1] > 0x8f) {
|
||||
this.clow += 0xff00;
|
||||
this.ct = 8;
|
||||
} else {
|
||||
bp++;
|
||||
this.clow += (data[bp] << 9);
|
||||
this.clow += data[bp] << 9;
|
||||
this.ct = 7;
|
||||
this.bp = bp;
|
||||
}
|
||||
} else {
|
||||
bp++;
|
||||
this.clow += bp < this.dataEnd ? (data[bp] << 8) : 0xFF00;
|
||||
this.clow += bp < this.dataEnd ? data[bp] << 8 : 0xff00;
|
||||
this.ct = 8;
|
||||
this.bp = bp;
|
||||
}
|
||||
if (this.clow > 0xFFFF) {
|
||||
this.chigh += (this.clow >> 16);
|
||||
this.clow &= 0xFFFF;
|
||||
if (this.clow > 0xffff) {
|
||||
this.chigh += this.clow >> 16;
|
||||
this.clow &= 0xffff;
|
||||
}
|
||||
}
|
||||
|
||||
@ -123,7 +123,8 @@ class ArithmeticDecoder {
|
||||
readBit(contexts, pos) {
|
||||
// Contexts are packed into 1 byte:
|
||||
// highest 7 bits carry cx.index, lowest bit carries cx.mps
|
||||
let cx_index = contexts[pos] >> 1, cx_mps = contexts[pos] & 1;
|
||||
let cx_index = contexts[pos] >> 1,
|
||||
cx_mps = contexts[pos] & 1;
|
||||
const qeTableIcx = QeTable[cx_index];
|
||||
const qeIcx = qeTableIcx.qe;
|
||||
let d;
|
||||
@ -168,17 +169,15 @@ class ArithmeticDecoder {
|
||||
}
|
||||
|
||||
a <<= 1;
|
||||
this.chigh = ((this.chigh << 1) & 0xFFFF) | ((this.clow >> 15) & 1);
|
||||
this.clow = (this.clow << 1) & 0xFFFF;
|
||||
this.chigh = ((this.chigh << 1) & 0xffff) | ((this.clow >> 15) & 1);
|
||||
this.clow = (this.clow << 1) & 0xffff;
|
||||
this.ct--;
|
||||
} while ((a & 0x8000) === 0);
|
||||
this.a = a;
|
||||
|
||||
contexts[pos] = cx_index << 1 | cx_mps;
|
||||
contexts[pos] = (cx_index << 1) | cx_mps;
|
||||
return d;
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
ArithmeticDecoder,
|
||||
};
|
||||
export { ArithmeticDecoder };
|
||||
|
183
src/core/bidi.js
183
src/core/bidi.js
@ -13,31 +13,32 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { warn } from '../shared/util';
|
||||
import { warn } from "../shared/util";
|
||||
|
||||
// Character types for symbols from 0000 to 00FF.
|
||||
// Source: ftp://ftp.unicode.org/Public/UNIDATA/UnicodeData.txt
|
||||
// prettier-ignore
|
||||
var baseTypes = [
|
||||
'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'S', 'B', 'S',
|
||||
'WS', 'B', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN',
|
||||
'BN', 'BN', 'BN', 'BN', 'B', 'B', 'B', 'S', 'WS', 'ON', 'ON', 'ET',
|
||||
'ET', 'ET', 'ON', 'ON', 'ON', 'ON', 'ON', 'ES', 'CS', 'ES', 'CS', 'CS',
|
||||
'EN', 'EN', 'EN', 'EN', 'EN', 'EN', 'EN', 'EN', 'EN', 'EN', 'CS', 'ON',
|
||||
'ON', 'ON', 'ON', 'ON', 'ON', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L',
|
||||
'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L',
|
||||
'L', 'L', 'L', 'L', 'ON', 'ON', 'ON', 'ON', 'ON', 'ON', 'L', 'L', 'L',
|
||||
'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L',
|
||||
'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'ON', 'ON', 'ON', 'ON',
|
||||
'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'B', 'BN', 'BN', 'BN', 'BN', 'BN',
|
||||
'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN',
|
||||
'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'CS', 'ON', 'ET',
|
||||
'ET', 'ET', 'ET', 'ON', 'ON', 'ON', 'ON', 'L', 'ON', 'ON', 'BN', 'ON',
|
||||
'ON', 'ET', 'ET', 'EN', 'EN', 'ON', 'L', 'ON', 'ON', 'ON', 'EN', 'L',
|
||||
'ON', 'ON', 'ON', 'ON', 'ON', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L',
|
||||
'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L',
|
||||
'L', 'ON', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L',
|
||||
'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L',
|
||||
'L', 'L', 'L', 'L', 'L', 'ON', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L'
|
||||
"BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "S", "B", "S",
|
||||
"WS", "B", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN",
|
||||
"BN", "BN", "BN", "BN", "B", "B", "B", "S", "WS", "ON", "ON", "ET",
|
||||
"ET", "ET", "ON", "ON", "ON", "ON", "ON", "ES", "CS", "ES", "CS", "CS",
|
||||
"EN", "EN", "EN", "EN", "EN", "EN", "EN", "EN", "EN", "EN", "CS", "ON",
|
||||
"ON", "ON", "ON", "ON", "ON", "L", "L", "L", "L", "L", "L", "L", "L",
|
||||
"L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L",
|
||||
"L", "L", "L", "L", "ON", "ON", "ON", "ON", "ON", "ON", "L", "L", "L",
|
||||
"L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L",
|
||||
"L", "L", "L", "L", "L", "L", "L", "L", "L", "ON", "ON", "ON", "ON",
|
||||
"BN", "BN", "BN", "BN", "BN", "BN", "B", "BN", "BN", "BN", "BN", "BN",
|
||||
"BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN",
|
||||
"BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "CS", "ON", "ET",
|
||||
"ET", "ET", "ET", "ON", "ON", "ON", "ON", "L", "ON", "ON", "BN", "ON",
|
||||
"ON", "ET", "ET", "EN", "EN", "ON", "L", "ON", "ON", "ON", "EN", "L",
|
||||
"ON", "ON", "ON", "ON", "ON", "L", "L", "L", "L", "L", "L", "L", "L",
|
||||
"L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L",
|
||||
"L", "ON", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L",
|
||||
"L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L",
|
||||
"L", "L", "L", "L", "L", "ON", "L", "L", "L", "L", "L", "L", "L", "L"
|
||||
];
|
||||
|
||||
// Character types for symbols from 0600 to 06FF.
|
||||
@ -46,29 +47,30 @@ var baseTypes = [
|
||||
// http://unicode.org/charts/PDF/U0600.pdf), so we replace it with an
|
||||
// empty string and issue a warning if we encounter this character. The
|
||||
// empty string is required to properly index the items after it.
|
||||
// prettier-ignore
|
||||
var arabicTypes = [
|
||||
'AN', 'AN', 'AN', 'AN', 'AN', 'AN', 'ON', 'ON', 'AL', 'ET', 'ET', 'AL',
|
||||
'CS', 'AL', 'ON', 'ON', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM',
|
||||
'NSM', 'NSM', 'NSM', 'NSM', 'AL', 'AL', '', 'AL', 'AL', 'AL', 'AL', 'AL',
|
||||
'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
|
||||
'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
|
||||
'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
|
||||
'AL', 'AL', 'AL', 'AL', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM',
|
||||
'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM',
|
||||
'NSM', 'NSM', 'NSM', 'NSM', 'AN', 'AN', 'AN', 'AN', 'AN', 'AN', 'AN',
|
||||
'AN', 'AN', 'AN', 'ET', 'AN', 'AN', 'AL', 'AL', 'AL', 'NSM', 'AL', 'AL',
|
||||
'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
|
||||
'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
|
||||
'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
|
||||
'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
|
||||
'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
|
||||
'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
|
||||
'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
|
||||
'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
|
||||
'AL', 'AL', 'AL', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'AN',
|
||||
'ON', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'AL', 'AL', 'NSM', 'NSM',
|
||||
'ON', 'NSM', 'NSM', 'NSM', 'NSM', 'AL', 'AL', 'EN', 'EN', 'EN', 'EN',
|
||||
'EN', 'EN', 'EN', 'EN', 'EN', 'EN', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL'
|
||||
"AN", "AN", "AN", "AN", "AN", "AN", "ON", "ON", "AL", "ET", "ET", "AL",
|
||||
"CS", "AL", "ON", "ON", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM",
|
||||
"NSM", "NSM", "NSM", "NSM", "AL", "AL", "", "AL", "AL", "AL", "AL", "AL",
|
||||
"AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL",
|
||||
"AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL",
|
||||
"AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL",
|
||||
"AL", "AL", "AL", "AL", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM",
|
||||
"NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM",
|
||||
"NSM", "NSM", "NSM", "NSM", "AN", "AN", "AN", "AN", "AN", "AN", "AN",
|
||||
"AN", "AN", "AN", "ET", "AN", "AN", "AL", "AL", "AL", "NSM", "AL", "AL",
|
||||
"AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL",
|
||||
"AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL",
|
||||
"AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL",
|
||||
"AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL",
|
||||
"AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL",
|
||||
"AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL",
|
||||
"AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL",
|
||||
"AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL",
|
||||
"AL", "AL", "AL", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "AN",
|
||||
"ON", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "AL", "AL", "NSM", "NSM",
|
||||
"ON", "NSM", "NSM", "NSM", "NSM", "AL", "AL", "EN", "EN", "EN", "EN",
|
||||
"EN", "EN", "EN", "EN", "EN", "EN", "AL", "AL", "AL", "AL", "AL", "AL"
|
||||
];
|
||||
|
||||
function isOdd(i) {
|
||||
@ -105,7 +107,7 @@ function reverseValues(arr, start, end) {
|
||||
function createBidiText(str, isLTR, vertical) {
|
||||
return {
|
||||
str,
|
||||
dir: (vertical ? 'ttb' : (isLTR ? 'ltr' : 'rtl')),
|
||||
dir: vertical ? "ttb" : isLTR ? "ltr" : "rtl",
|
||||
};
|
||||
}
|
||||
|
||||
@ -131,20 +133,20 @@ function bidi(str, startLevel, vertical) {
|
||||
chars[i] = str.charAt(i);
|
||||
|
||||
var charCode = str.charCodeAt(i);
|
||||
var charType = 'L';
|
||||
var charType = "L";
|
||||
if (charCode <= 0x00ff) {
|
||||
charType = baseTypes[charCode];
|
||||
} else if (0x0590 <= charCode && charCode <= 0x05f4) {
|
||||
charType = 'R';
|
||||
charType = "R";
|
||||
} else if (0x0600 <= charCode && charCode <= 0x06ff) {
|
||||
charType = arabicTypes[charCode & 0xff];
|
||||
if (!charType) {
|
||||
warn('Bidi: invalid Unicode character ' + charCode.toString(16));
|
||||
warn("Bidi: invalid Unicode character " + charCode.toString(16));
|
||||
}
|
||||
} else if (0x0700 <= charCode && charCode <= 0x08AC) {
|
||||
charType = 'AL';
|
||||
} else if (0x0700 <= charCode && charCode <= 0x08ac) {
|
||||
charType = "AL";
|
||||
}
|
||||
if (charType === 'R' || charType === 'AL' || charType === 'AN') {
|
||||
if (charType === "R" || charType === "AL" || charType === "AN") {
|
||||
numBidi++;
|
||||
}
|
||||
types[i] = charType;
|
||||
@ -160,7 +162,7 @@ function bidi(str, startLevel, vertical) {
|
||||
}
|
||||
|
||||
if (startLevel === -1) {
|
||||
if ((numBidi / strLength) < 0.3) {
|
||||
if (numBidi / strLength < 0.3) {
|
||||
isLTR = true;
|
||||
startLevel = 0;
|
||||
} else {
|
||||
@ -177,7 +179,7 @@ function bidi(str, startLevel, vertical) {
|
||||
/*
|
||||
X1-X10: skip most of this, since we are NOT doing the embeddings.
|
||||
*/
|
||||
var e = (isOdd(startLevel) ? 'R' : 'L');
|
||||
var e = isOdd(startLevel) ? "R" : "L";
|
||||
var sor = e;
|
||||
var eor = sor;
|
||||
|
||||
@ -188,7 +190,7 @@ function bidi(str, startLevel, vertical) {
|
||||
*/
|
||||
var lastType = sor;
|
||||
for (i = 0; i < strLength; ++i) {
|
||||
if (types[i] === 'NSM') {
|
||||
if (types[i] === "NSM") {
|
||||
types[i] = lastType;
|
||||
} else {
|
||||
lastType = types[i];
|
||||
@ -204,9 +206,9 @@ function bidi(str, startLevel, vertical) {
|
||||
var t;
|
||||
for (i = 0; i < strLength; ++i) {
|
||||
t = types[i];
|
||||
if (t === 'EN') {
|
||||
types[i] = (lastType === 'AL') ? 'AN' : 'EN';
|
||||
} else if (t === 'R' || t === 'L' || t === 'AL') {
|
||||
if (t === "EN") {
|
||||
types[i] = lastType === "AL" ? "AN" : "EN";
|
||||
} else if (t === "R" || t === "L" || t === "AL") {
|
||||
lastType = t;
|
||||
}
|
||||
}
|
||||
@ -216,8 +218,8 @@ function bidi(str, startLevel, vertical) {
|
||||
*/
|
||||
for (i = 0; i < strLength; ++i) {
|
||||
t = types[i];
|
||||
if (t === 'AL') {
|
||||
types[i] = 'R';
|
||||
if (t === "AL") {
|
||||
types[i] = "R";
|
||||
}
|
||||
}
|
||||
|
||||
@ -227,12 +229,14 @@ function bidi(str, startLevel, vertical) {
|
||||
type changes to that type:
|
||||
*/
|
||||
for (i = 1; i < strLength - 1; ++i) {
|
||||
if (types[i] === 'ES' && types[i - 1] === 'EN' && types[i + 1] === 'EN') {
|
||||
types[i] = 'EN';
|
||||
if (types[i] === "ES" && types[i - 1] === "EN" && types[i + 1] === "EN") {
|
||||
types[i] = "EN";
|
||||
}
|
||||
if (types[i] === 'CS' &&
|
||||
(types[i - 1] === 'EN' || types[i - 1] === 'AN') &&
|
||||
types[i + 1] === types[i - 1]) {
|
||||
if (
|
||||
types[i] === "CS" &&
|
||||
(types[i - 1] === "EN" || types[i - 1] === "AN") &&
|
||||
types[i + 1] === types[i - 1]
|
||||
) {
|
||||
types[i] = types[i - 1];
|
||||
}
|
||||
}
|
||||
@ -242,21 +246,21 @@ function bidi(str, startLevel, vertical) {
|
||||
to all European numbers:
|
||||
*/
|
||||
for (i = 0; i < strLength; ++i) {
|
||||
if (types[i] === 'EN') {
|
||||
if (types[i] === "EN") {
|
||||
// do before
|
||||
var j;
|
||||
for (j = i - 1; j >= 0; --j) {
|
||||
if (types[j] !== 'ET') {
|
||||
if (types[j] !== "ET") {
|
||||
break;
|
||||
}
|
||||
types[j] = 'EN';
|
||||
types[j] = "EN";
|
||||
}
|
||||
// do after
|
||||
for (j = i + 1; j < strLength; ++j) {
|
||||
if (types[j] !== 'ET') {
|
||||
if (types[j] !== "ET") {
|
||||
break;
|
||||
}
|
||||
types[j] = 'EN';
|
||||
types[j] = "EN";
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -266,8 +270,8 @@ function bidi(str, startLevel, vertical) {
|
||||
*/
|
||||
for (i = 0; i < strLength; ++i) {
|
||||
t = types[i];
|
||||
if (t === 'WS' || t === 'ES' || t === 'ET' || t === 'CS') {
|
||||
types[i] = 'ON';
|
||||
if (t === "WS" || t === "ES" || t === "ET" || t === "CS") {
|
||||
types[i] = "ON";
|
||||
}
|
||||
}
|
||||
|
||||
@ -279,9 +283,9 @@ function bidi(str, startLevel, vertical) {
|
||||
lastType = sor;
|
||||
for (i = 0; i < strLength; ++i) {
|
||||
t = types[i];
|
||||
if (t === 'EN') {
|
||||
types[i] = ((lastType === 'L') ? 'L' : 'EN');
|
||||
} else if (t === 'R' || t === 'L') {
|
||||
if (t === "EN") {
|
||||
types[i] = lastType === "L" ? "L" : "EN";
|
||||
} else if (t === "R" || t === "L") {
|
||||
lastType = t;
|
||||
}
|
||||
}
|
||||
@ -293,8 +297,8 @@ function bidi(str, startLevel, vertical) {
|
||||
end-of-level-run (eor) are used at level run boundaries.
|
||||
*/
|
||||
for (i = 0; i < strLength; ++i) {
|
||||
if (types[i] === 'ON') {
|
||||
var end = findUnequal(types, i + 1, 'ON');
|
||||
if (types[i] === "ON") {
|
||||
var end = findUnequal(types, i + 1, "ON");
|
||||
var before = sor;
|
||||
if (i > 0) {
|
||||
before = types[i - 1];
|
||||
@ -304,11 +308,11 @@ function bidi(str, startLevel, vertical) {
|
||||
if (end + 1 < strLength) {
|
||||
after = types[end + 1];
|
||||
}
|
||||
if (before !== 'L') {
|
||||
before = 'R';
|
||||
if (before !== "L") {
|
||||
before = "R";
|
||||
}
|
||||
if (after !== 'L') {
|
||||
after = 'R';
|
||||
if (after !== "L") {
|
||||
after = "R";
|
||||
}
|
||||
if (before === after) {
|
||||
setValues(types, i, end, before);
|
||||
@ -321,7 +325,7 @@ function bidi(str, startLevel, vertical) {
|
||||
N2. Any remaining neutrals take the embedding direction.
|
||||
*/
|
||||
for (i = 0; i < strLength; ++i) {
|
||||
if (types[i] === 'ON') {
|
||||
if (types[i] === "ON") {
|
||||
types[i] = e;
|
||||
}
|
||||
}
|
||||
@ -336,13 +340,14 @@ function bidi(str, startLevel, vertical) {
|
||||
for (i = 0; i < strLength; ++i) {
|
||||
t = types[i];
|
||||
if (isEven(levels[i])) {
|
||||
if (t === 'R') {
|
||||
if (t === "R") {
|
||||
levels[i] += 1;
|
||||
} else if (t === 'AN' || t === 'EN') {
|
||||
} else if (t === "AN" || t === "EN") {
|
||||
levels[i] += 2;
|
||||
}
|
||||
} else { // isOdd
|
||||
if (t === 'L' || t === 'AN' || t === 'EN') {
|
||||
} else {
|
||||
// isOdd
|
||||
if (t === "L" || t === "AN" || t === "EN") {
|
||||
levels[i] += 1;
|
||||
}
|
||||
}
|
||||
@ -420,13 +425,11 @@ function bidi(str, startLevel, vertical) {
|
||||
// Finally, return string
|
||||
for (i = 0, ii = chars.length; i < ii; ++i) {
|
||||
var ch = chars[i];
|
||||
if (ch === '<' || ch === '>') {
|
||||
chars[i] = '';
|
||||
if (ch === "<" || ch === ">") {
|
||||
chars[i] = "";
|
||||
}
|
||||
}
|
||||
return createBidiText(chars.join(''), isLTR);
|
||||
return createBidiText(chars.join(""), isLTR);
|
||||
}
|
||||
|
||||
export {
|
||||
bidi,
|
||||
};
|
||||
export { bidi };
|
||||
|
@ -25,10 +25,9 @@
|
||||
* or -1 when EOF is reached.
|
||||
*/
|
||||
|
||||
import { info } from '../shared/util';
|
||||
import { info } from "../shared/util";
|
||||
|
||||
let CCITTFaxDecoder = (function CCITTFaxDecoder() {
|
||||
|
||||
const ccittEOL = -2;
|
||||
const ccittEOF = -1;
|
||||
const twoDimPass = 0;
|
||||
@ -41,6 +40,7 @@ let CCITTFaxDecoder = (function CCITTFaxDecoder() {
|
||||
const twoDimVertR3 = 7;
|
||||
const twoDimVertL3 = 8;
|
||||
|
||||
// prettier-ignore
|
||||
const twoDimTable = [
|
||||
[-1, -1], [-1, -1], // 000000x
|
||||
[7, twoDimVertL3], // 0000010
|
||||
@ -109,6 +109,7 @@ let CCITTFaxDecoder = (function CCITTFaxDecoder() {
|
||||
[1, twoDimVert0], [1, twoDimVert0]
|
||||
];
|
||||
|
||||
// prettier-ignore
|
||||
const whiteTable1 = [
|
||||
[-1, -1], // 00000
|
||||
[12, ccittEOL], // 00001
|
||||
@ -131,6 +132,7 @@ let CCITTFaxDecoder = (function CCITTFaxDecoder() {
|
||||
[12, 2560] // 11111
|
||||
];
|
||||
|
||||
// prettier-ignore
|
||||
const whiteTable2 = [
|
||||
[-1, -1], [-1, -1], [-1, -1], [-1, -1], // 0000000xx
|
||||
[8, 29], [8, 29], // 00000010x
|
||||
@ -295,6 +297,7 @@ let CCITTFaxDecoder = (function CCITTFaxDecoder() {
|
||||
[4, 7], [4, 7], [4, 7], [4, 7]
|
||||
];
|
||||
|
||||
// prettier-ignore
|
||||
const blackTable1 = [
|
||||
[-1, -1], [-1, -1], // 000000000000x
|
||||
[12, ccittEOL], [12, ccittEOL], // 000000000001x
|
||||
@ -356,6 +359,7 @@ let CCITTFaxDecoder = (function CCITTFaxDecoder() {
|
||||
[10, 64], [10, 64], [10, 64], [10, 64]
|
||||
];
|
||||
|
||||
// prettier-ignore
|
||||
const blackTable2 = [
|
||||
[8, 13], [8, 13], [8, 13], [8, 13], // 00000100xxxx
|
||||
[8, 13], [8, 13], [8, 13], [8, 13],
|
||||
@ -435,6 +439,7 @@ let CCITTFaxDecoder = (function CCITTFaxDecoder() {
|
||||
[7, 12], [7, 12], [7, 12], [7, 12]
|
||||
];
|
||||
|
||||
// prettier-ignore
|
||||
const blackTable3 = [
|
||||
[-1, -1], [-1, -1], [-1, -1], [-1, -1], // 0000xx
|
||||
[6, 9], // 000100
|
||||
@ -461,23 +466,23 @@ let CCITTFaxDecoder = (function CCITTFaxDecoder() {
|
||||
* @param {Object} [options] - Decoding options.
|
||||
*/
|
||||
function CCITTFaxDecoder(source, options = {}) {
|
||||
if (!source || typeof source.next !== 'function') {
|
||||
if (!source || typeof source.next !== "function") {
|
||||
throw new Error('CCITTFaxDecoder - invalid "source" parameter.');
|
||||
}
|
||||
this.source = source;
|
||||
this.eof = false;
|
||||
|
||||
this.encoding = options['K'] || 0;
|
||||
this.eoline = options['EndOfLine'] || false;
|
||||
this.byteAlign = options['EncodedByteAlign'] || false;
|
||||
this.columns = options['Columns'] || 1728;
|
||||
this.rows = options['Rows'] || 0;
|
||||
let eoblock = options['EndOfBlock'];
|
||||
this.encoding = options["K"] || 0;
|
||||
this.eoline = options["EndOfLine"] || false;
|
||||
this.byteAlign = options["EncodedByteAlign"] || false;
|
||||
this.columns = options["Columns"] || 1728;
|
||||
this.rows = options["Rows"] || 0;
|
||||
let eoblock = options["EndOfBlock"];
|
||||
if (eoblock === null || eoblock === undefined) {
|
||||
eoblock = true;
|
||||
}
|
||||
this.eoblock = eoblock;
|
||||
this.black = options['BlackIs1'] || false;
|
||||
this.black = options["BlackIs1"] || false;
|
||||
|
||||
this.codingLine = new Uint32Array(this.columns + 1);
|
||||
this.refLine = new Uint32Array(this.columns + 2);
|
||||
@ -550,27 +555,33 @@ let CCITTFaxDecoder = (function CCITTFaxDecoder() {
|
||||
code1 = code2 = 0;
|
||||
if (blackPixels) {
|
||||
do {
|
||||
code1 += (code3 = this._getBlackCode());
|
||||
code1 += code3 = this._getBlackCode();
|
||||
} while (code3 >= 64);
|
||||
do {
|
||||
code2 += (code3 = this._getWhiteCode());
|
||||
code2 += code3 = this._getWhiteCode();
|
||||
} while (code3 >= 64);
|
||||
} else {
|
||||
do {
|
||||
code1 += (code3 = this._getWhiteCode());
|
||||
code1 += code3 = this._getWhiteCode();
|
||||
} while (code3 >= 64);
|
||||
do {
|
||||
code2 += (code3 = this._getBlackCode());
|
||||
code2 += code3 = this._getBlackCode();
|
||||
} while (code3 >= 64);
|
||||
}
|
||||
this._addPixels(codingLine[this.codingPos] +
|
||||
code1, blackPixels);
|
||||
this._addPixels(
|
||||
codingLine[this.codingPos] + code1,
|
||||
blackPixels
|
||||
);
|
||||
if (codingLine[this.codingPos] < columns) {
|
||||
this._addPixels(codingLine[this.codingPos] + code2,
|
||||
blackPixels ^ 1);
|
||||
this._addPixels(
|
||||
codingLine[this.codingPos] + code2,
|
||||
blackPixels ^ 1
|
||||
);
|
||||
}
|
||||
while (refLine[refPos] <= codingLine[this.codingPos] &&
|
||||
refLine[refPos] < columns) {
|
||||
while (
|
||||
refLine[refPos] <= codingLine[this.codingPos] &&
|
||||
refLine[refPos] < columns
|
||||
) {
|
||||
refPos += 2;
|
||||
}
|
||||
break;
|
||||
@ -579,8 +590,10 @@ let CCITTFaxDecoder = (function CCITTFaxDecoder() {
|
||||
blackPixels ^= 1;
|
||||
if (codingLine[this.codingPos] < columns) {
|
||||
++refPos;
|
||||
while (refLine[refPos] <= codingLine[this.codingPos] &&
|
||||
refLine[refPos] < columns) {
|
||||
while (
|
||||
refLine[refPos] <= codingLine[this.codingPos] &&
|
||||
refLine[refPos] < columns
|
||||
) {
|
||||
refPos += 2;
|
||||
}
|
||||
}
|
||||
@ -590,8 +603,10 @@ let CCITTFaxDecoder = (function CCITTFaxDecoder() {
|
||||
blackPixels ^= 1;
|
||||
if (codingLine[this.codingPos] < columns) {
|
||||
++refPos;
|
||||
while (refLine[refPos] <= codingLine[this.codingPos] &&
|
||||
refLine[refPos] < columns) {
|
||||
while (
|
||||
refLine[refPos] <= codingLine[this.codingPos] &&
|
||||
refLine[refPos] < columns
|
||||
) {
|
||||
refPos += 2;
|
||||
}
|
||||
}
|
||||
@ -601,8 +616,10 @@ let CCITTFaxDecoder = (function CCITTFaxDecoder() {
|
||||
blackPixels ^= 1;
|
||||
if (codingLine[this.codingPos] < columns) {
|
||||
++refPos;
|
||||
while (refLine[refPos] <= codingLine[this.codingPos] &&
|
||||
refLine[refPos] < columns) {
|
||||
while (
|
||||
refLine[refPos] <= codingLine[this.codingPos] &&
|
||||
refLine[refPos] < columns
|
||||
) {
|
||||
refPos += 2;
|
||||
}
|
||||
}
|
||||
@ -612,8 +629,10 @@ let CCITTFaxDecoder = (function CCITTFaxDecoder() {
|
||||
blackPixels ^= 1;
|
||||
if (codingLine[this.codingPos] < columns) {
|
||||
++refPos;
|
||||
while (refLine[refPos] <= codingLine[this.codingPos] &&
|
||||
refLine[refPos] < columns) {
|
||||
while (
|
||||
refLine[refPos] <= codingLine[this.codingPos] &&
|
||||
refLine[refPos] < columns
|
||||
) {
|
||||
refPos += 2;
|
||||
}
|
||||
}
|
||||
@ -627,8 +646,10 @@ let CCITTFaxDecoder = (function CCITTFaxDecoder() {
|
||||
} else {
|
||||
++refPos;
|
||||
}
|
||||
while (refLine[refPos] <= codingLine[this.codingPos] &&
|
||||
refLine[refPos] < columns) {
|
||||
while (
|
||||
refLine[refPos] <= codingLine[this.codingPos] &&
|
||||
refLine[refPos] < columns
|
||||
) {
|
||||
refPos += 2;
|
||||
}
|
||||
}
|
||||
@ -642,8 +663,10 @@ let CCITTFaxDecoder = (function CCITTFaxDecoder() {
|
||||
} else {
|
||||
++refPos;
|
||||
}
|
||||
while (refLine[refPos] <= codingLine[this.codingPos] &&
|
||||
refLine[refPos] < columns) {
|
||||
while (
|
||||
refLine[refPos] <= codingLine[this.codingPos] &&
|
||||
refLine[refPos] < columns
|
||||
) {
|
||||
refPos += 2;
|
||||
}
|
||||
}
|
||||
@ -657,8 +680,10 @@ let CCITTFaxDecoder = (function CCITTFaxDecoder() {
|
||||
} else {
|
||||
++refPos;
|
||||
}
|
||||
while (refLine[refPos] <= codingLine[this.codingPos] &&
|
||||
refLine[refPos] < columns) {
|
||||
while (
|
||||
refLine[refPos] <= codingLine[this.codingPos] &&
|
||||
refLine[refPos] < columns
|
||||
) {
|
||||
refPos += 2;
|
||||
}
|
||||
}
|
||||
@ -668,7 +693,7 @@ let CCITTFaxDecoder = (function CCITTFaxDecoder() {
|
||||
this.eof = true;
|
||||
break;
|
||||
default:
|
||||
info('bad 2d code');
|
||||
info("bad 2d code");
|
||||
this._addPixels(columns, 0);
|
||||
this.err = true;
|
||||
}
|
||||
@ -681,11 +706,11 @@ let CCITTFaxDecoder = (function CCITTFaxDecoder() {
|
||||
code1 = 0;
|
||||
if (blackPixels) {
|
||||
do {
|
||||
code1 += (code3 = this._getBlackCode());
|
||||
code1 += code3 = this._getBlackCode();
|
||||
} while (code3 >= 64);
|
||||
} else {
|
||||
do {
|
||||
code1 += (code3 = this._getWhiteCode());
|
||||
code1 += code3 = this._getWhiteCode();
|
||||
} while (code3 >= 64);
|
||||
}
|
||||
this._addPixels(codingLine[this.codingPos] + code1, blackPixels);
|
||||
@ -739,7 +764,7 @@ let CCITTFaxDecoder = (function CCITTFaxDecoder() {
|
||||
for (i = 0; i < 4; ++i) {
|
||||
code1 = this._lookBits(12);
|
||||
if (code1 !== 1) {
|
||||
info('bad rtc code: ' + code1);
|
||||
info("bad rtc code: " + code1);
|
||||
}
|
||||
this._eatBits(12);
|
||||
if (this.encoding > 0) {
|
||||
@ -757,7 +782,7 @@ let CCITTFaxDecoder = (function CCITTFaxDecoder() {
|
||||
this.eof = true;
|
||||
return -1;
|
||||
}
|
||||
if ((code1 >> 1) === 1) {
|
||||
if (code1 >> 1 === 1) {
|
||||
break;
|
||||
}
|
||||
this._eatBits(1);
|
||||
@ -770,21 +795,21 @@ let CCITTFaxDecoder = (function CCITTFaxDecoder() {
|
||||
}
|
||||
|
||||
if (codingLine[0] > 0) {
|
||||
this.outputBits = codingLine[this.codingPos = 0];
|
||||
this.outputBits = codingLine[(this.codingPos = 0)];
|
||||
} else {
|
||||
this.outputBits = codingLine[this.codingPos = 1];
|
||||
this.outputBits = codingLine[(this.codingPos = 1)];
|
||||
}
|
||||
this.row++;
|
||||
}
|
||||
|
||||
let c;
|
||||
if (this.outputBits >= 8) {
|
||||
c = (this.codingPos & 1) ? 0 : 0xFF;
|
||||
c = this.codingPos & 1 ? 0 : 0xff;
|
||||
this.outputBits -= 8;
|
||||
if (this.outputBits === 0 && codingLine[this.codingPos] < columns) {
|
||||
this.codingPos++;
|
||||
this.outputBits = (codingLine[this.codingPos] -
|
||||
codingLine[this.codingPos - 1]);
|
||||
this.outputBits =
|
||||
codingLine[this.codingPos] - codingLine[this.codingPos - 1];
|
||||
}
|
||||
} else {
|
||||
bits = 8;
|
||||
@ -793,21 +818,21 @@ let CCITTFaxDecoder = (function CCITTFaxDecoder() {
|
||||
if (this.outputBits > bits) {
|
||||
c <<= bits;
|
||||
if (!(this.codingPos & 1)) {
|
||||
c |= 0xFF >> (8 - bits);
|
||||
c |= 0xff >> (8 - bits);
|
||||
}
|
||||
this.outputBits -= bits;
|
||||
bits = 0;
|
||||
} else {
|
||||
c <<= this.outputBits;
|
||||
if (!(this.codingPos & 1)) {
|
||||
c |= 0xFF >> (8 - this.outputBits);
|
||||
c |= 0xff >> (8 - this.outputBits);
|
||||
}
|
||||
bits -= this.outputBits;
|
||||
this.outputBits = 0;
|
||||
if (codingLine[this.codingPos] < columns) {
|
||||
this.codingPos++;
|
||||
this.outputBits = (codingLine[this.codingPos] -
|
||||
codingLine[this.codingPos - 1]);
|
||||
this.outputBits =
|
||||
codingLine[this.codingPos] - codingLine[this.codingPos - 1];
|
||||
} else if (bits > 0) {
|
||||
c <<= bits;
|
||||
bits = 0;
|
||||
@ -816,7 +841,7 @@ let CCITTFaxDecoder = (function CCITTFaxDecoder() {
|
||||
} while (bits);
|
||||
}
|
||||
if (this.black) {
|
||||
c ^= 0xFF;
|
||||
c ^= 0xff;
|
||||
}
|
||||
return c;
|
||||
},
|
||||
@ -830,7 +855,7 @@ let CCITTFaxDecoder = (function CCITTFaxDecoder() {
|
||||
|
||||
if (a1 > codingLine[codingPos]) {
|
||||
if (a1 > this.columns) {
|
||||
info('row is wrong length');
|
||||
info("row is wrong length");
|
||||
this.err = true;
|
||||
a1 = this.columns;
|
||||
}
|
||||
@ -852,7 +877,7 @@ let CCITTFaxDecoder = (function CCITTFaxDecoder() {
|
||||
|
||||
if (a1 > codingLine[codingPos]) {
|
||||
if (a1 > this.columns) {
|
||||
info('row is wrong length');
|
||||
info("row is wrong length");
|
||||
this.err = true;
|
||||
a1 = this.columns;
|
||||
}
|
||||
@ -863,7 +888,7 @@ let CCITTFaxDecoder = (function CCITTFaxDecoder() {
|
||||
codingLine[codingPos] = a1;
|
||||
} else if (a1 < codingLine[codingPos]) {
|
||||
if (a1 < 0) {
|
||||
info('invalid code');
|
||||
info("invalid code");
|
||||
this.err = true;
|
||||
a1 = 0;
|
||||
}
|
||||
@ -925,7 +950,7 @@ let CCITTFaxDecoder = (function CCITTFaxDecoder() {
|
||||
return result[1];
|
||||
}
|
||||
}
|
||||
info('Bad two dim code');
|
||||
info("Bad two dim code");
|
||||
return ccittEOF;
|
||||
},
|
||||
|
||||
@ -941,7 +966,7 @@ let CCITTFaxDecoder = (function CCITTFaxDecoder() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((code >> 5) === 0) {
|
||||
if (code >> 5 === 0) {
|
||||
p = whiteTable1[code];
|
||||
} else {
|
||||
p = whiteTable2[code >> 3];
|
||||
@ -962,7 +987,7 @@ let CCITTFaxDecoder = (function CCITTFaxDecoder() {
|
||||
return result[1];
|
||||
}
|
||||
}
|
||||
info('bad white code');
|
||||
info("bad white code");
|
||||
this._eatBits(1);
|
||||
return 1;
|
||||
},
|
||||
@ -977,9 +1002,9 @@ let CCITTFaxDecoder = (function CCITTFaxDecoder() {
|
||||
if (code === ccittEOF) {
|
||||
return 1;
|
||||
}
|
||||
if ((code >> 7) === 0) {
|
||||
if (code >> 7 === 0) {
|
||||
p = blackTable1[code];
|
||||
} else if ((code >> 9) === 0 && (code >> 7) !== 0) {
|
||||
} else if (code >> 9 === 0 && code >> 7 !== 0) {
|
||||
p = blackTable2[(code >> 1) - 64];
|
||||
} else {
|
||||
p = blackTable3[code >> 7];
|
||||
@ -1005,7 +1030,7 @@ let CCITTFaxDecoder = (function CCITTFaxDecoder() {
|
||||
return result[1];
|
||||
}
|
||||
}
|
||||
info('bad black code');
|
||||
info("bad black code");
|
||||
this._eatBits(1);
|
||||
return 1;
|
||||
},
|
||||
@ -1020,13 +1045,12 @@ let CCITTFaxDecoder = (function CCITTFaxDecoder() {
|
||||
if (this.inputBits === 0) {
|
||||
return ccittEOF;
|
||||
}
|
||||
return ((this.inputBuf << (n - this.inputBits)) &
|
||||
(0xFFFF >> (16 - n)));
|
||||
return (this.inputBuf << (n - this.inputBits)) & (0xffff >> (16 - n));
|
||||
}
|
||||
this.inputBuf = (this.inputBuf << 8) | c;
|
||||
this.inputBits += 8;
|
||||
}
|
||||
return (this.inputBuf >> (this.inputBits - n)) & (0xFFFF >> (16 - n));
|
||||
return (this.inputBuf >> (this.inputBits - n)) & (0xffff >> (16 - n));
|
||||
},
|
||||
|
||||
/**
|
||||
@ -1042,6 +1066,4 @@ let CCITTFaxDecoder = (function CCITTFaxDecoder() {
|
||||
return CCITTFaxDecoder;
|
||||
})();
|
||||
|
||||
export {
|
||||
CCITTFaxDecoder,
|
||||
};
|
||||
export { CCITTFaxDecoder };
|
||||
|
@ -13,9 +13,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Dict, isDict } from './primitives';
|
||||
import { CCITTFaxDecoder } from './ccitt';
|
||||
import { DecodeStream } from './stream';
|
||||
import { Dict, isDict } from "./primitives";
|
||||
import { CCITTFaxDecoder } from "./ccitt";
|
||||
import { DecodeStream } from "./stream";
|
||||
|
||||
var CCITTFaxStream = (function CCITTFaxStreamClosure() {
|
||||
function CCITTFaxStream(str, maybeLength, params) {
|
||||
@ -32,13 +32,13 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
|
||||
},
|
||||
};
|
||||
this.ccittFaxDecoder = new CCITTFaxDecoder(source, {
|
||||
K: params.get('K'),
|
||||
EndOfLine: params.get('EndOfLine'),
|
||||
EncodedByteAlign: params.get('EncodedByteAlign'),
|
||||
Columns: params.get('Columns'),
|
||||
Rows: params.get('Rows'),
|
||||
EndOfBlock: params.get('EndOfBlock'),
|
||||
BlackIs1: params.get('BlackIs1'),
|
||||
K: params.get("K"),
|
||||
EndOfLine: params.get("EndOfLine"),
|
||||
EncodedByteAlign: params.get("EncodedByteAlign"),
|
||||
Columns: params.get("Columns"),
|
||||
Rows: params.get("Rows"),
|
||||
EndOfBlock: params.get("EndOfBlock"),
|
||||
BlackIs1: params.get("BlackIs1"),
|
||||
});
|
||||
|
||||
DecodeStream.call(this, maybeLength);
|
||||
@ -61,6 +61,4 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
|
||||
return CCITTFaxStream;
|
||||
})();
|
||||
|
||||
export {
|
||||
CCITTFaxStream,
|
||||
};
|
||||
export { CCITTFaxStream };
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -14,108 +14,107 @@
|
||||
*/
|
||||
/* eslint no-var: error */
|
||||
|
||||
// prettier-ignore
|
||||
const ISOAdobeCharset = [
|
||||
'.notdef', 'space', 'exclam', 'quotedbl', 'numbersign', 'dollar',
|
||||
'percent', 'ampersand', 'quoteright', 'parenleft', 'parenright',
|
||||
'asterisk', 'plus', 'comma', 'hyphen', 'period', 'slash', 'zero',
|
||||
'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight',
|
||||
'nine', 'colon', 'semicolon', 'less', 'equal', 'greater', 'question',
|
||||
'at', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
|
||||
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
|
||||
'bracketleft', 'backslash', 'bracketright', 'asciicircum', 'underscore',
|
||||
'quoteleft', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
|
||||
'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
|
||||
'braceleft', 'bar', 'braceright', 'asciitilde', 'exclamdown', 'cent',
|
||||
'sterling', 'fraction', 'yen', 'florin', 'section', 'currency',
|
||||
'quotesingle', 'quotedblleft', 'guillemotleft', 'guilsinglleft',
|
||||
'guilsinglright', 'fi', 'fl', 'endash', 'dagger', 'daggerdbl',
|
||||
'periodcentered', 'paragraph', 'bullet', 'quotesinglbase',
|
||||
'quotedblbase', 'quotedblright', 'guillemotright', 'ellipsis',
|
||||
'perthousand', 'questiondown', 'grave', 'acute', 'circumflex', 'tilde',
|
||||
'macron', 'breve', 'dotaccent', 'dieresis', 'ring', 'cedilla',
|
||||
'hungarumlaut', 'ogonek', 'caron', 'emdash', 'AE', 'ordfeminine',
|
||||
'Lslash', 'Oslash', 'OE', 'ordmasculine', 'ae', 'dotlessi', 'lslash',
|
||||
'oslash', 'oe', 'germandbls', 'onesuperior', 'logicalnot', 'mu',
|
||||
'trademark', 'Eth', 'onehalf', 'plusminus', 'Thorn', 'onequarter',
|
||||
'divide', 'brokenbar', 'degree', 'thorn', 'threequarters', 'twosuperior',
|
||||
'registered', 'minus', 'eth', 'multiply', 'threesuperior', 'copyright',
|
||||
'Aacute', 'Acircumflex', 'Adieresis', 'Agrave', 'Aring', 'Atilde',
|
||||
'Ccedilla', 'Eacute', 'Ecircumflex', 'Edieresis', 'Egrave', 'Iacute',
|
||||
'Icircumflex', 'Idieresis', 'Igrave', 'Ntilde', 'Oacute', 'Ocircumflex',
|
||||
'Odieresis', 'Ograve', 'Otilde', 'Scaron', 'Uacute', 'Ucircumflex',
|
||||
'Udieresis', 'Ugrave', 'Yacute', 'Ydieresis', 'Zcaron', 'aacute',
|
||||
'acircumflex', 'adieresis', 'agrave', 'aring', 'atilde', 'ccedilla',
|
||||
'eacute', 'ecircumflex', 'edieresis', 'egrave', 'iacute', 'icircumflex',
|
||||
'idieresis', 'igrave', 'ntilde', 'oacute', 'ocircumflex', 'odieresis',
|
||||
'ograve', 'otilde', 'scaron', 'uacute', 'ucircumflex', 'udieresis',
|
||||
'ugrave', 'yacute', 'ydieresis', 'zcaron'
|
||||
".notdef", "space", "exclam", "quotedbl", "numbersign", "dollar",
|
||||
"percent", "ampersand", "quoteright", "parenleft", "parenright",
|
||||
"asterisk", "plus", "comma", "hyphen", "period", "slash", "zero",
|
||||
"one", "two", "three", "four", "five", "six", "seven", "eight",
|
||||
"nine", "colon", "semicolon", "less", "equal", "greater", "question",
|
||||
"at", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M",
|
||||
"N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
|
||||
"bracketleft", "backslash", "bracketright", "asciicircum", "underscore",
|
||||
"quoteleft", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l",
|
||||
"m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
|
||||
"braceleft", "bar", "braceright", "asciitilde", "exclamdown", "cent",
|
||||
"sterling", "fraction", "yen", "florin", "section", "currency",
|
||||
"quotesingle", "quotedblleft", "guillemotleft", "guilsinglleft",
|
||||
"guilsinglright", "fi", "fl", "endash", "dagger", "daggerdbl",
|
||||
"periodcentered", "paragraph", "bullet", "quotesinglbase",
|
||||
"quotedblbase", "quotedblright", "guillemotright", "ellipsis",
|
||||
"perthousand", "questiondown", "grave", "acute", "circumflex", "tilde",
|
||||
"macron", "breve", "dotaccent", "dieresis", "ring", "cedilla",
|
||||
"hungarumlaut", "ogonek", "caron", "emdash", "AE", "ordfeminine",
|
||||
"Lslash", "Oslash", "OE", "ordmasculine", "ae", "dotlessi", "lslash",
|
||||
"oslash", "oe", "germandbls", "onesuperior", "logicalnot", "mu",
|
||||
"trademark", "Eth", "onehalf", "plusminus", "Thorn", "onequarter",
|
||||
"divide", "brokenbar", "degree", "thorn", "threequarters", "twosuperior",
|
||||
"registered", "minus", "eth", "multiply", "threesuperior", "copyright",
|
||||
"Aacute", "Acircumflex", "Adieresis", "Agrave", "Aring", "Atilde",
|
||||
"Ccedilla", "Eacute", "Ecircumflex", "Edieresis", "Egrave", "Iacute",
|
||||
"Icircumflex", "Idieresis", "Igrave", "Ntilde", "Oacute", "Ocircumflex",
|
||||
"Odieresis", "Ograve", "Otilde", "Scaron", "Uacute", "Ucircumflex",
|
||||
"Udieresis", "Ugrave", "Yacute", "Ydieresis", "Zcaron", "aacute",
|
||||
"acircumflex", "adieresis", "agrave", "aring", "atilde", "ccedilla",
|
||||
"eacute", "ecircumflex", "edieresis", "egrave", "iacute", "icircumflex",
|
||||
"idieresis", "igrave", "ntilde", "oacute", "ocircumflex", "odieresis",
|
||||
"ograve", "otilde", "scaron", "uacute", "ucircumflex", "udieresis",
|
||||
"ugrave", "yacute", "ydieresis", "zcaron"
|
||||
];
|
||||
|
||||
// prettier-ignore
|
||||
const ExpertCharset = [
|
||||
'.notdef', 'space', 'exclamsmall', 'Hungarumlautsmall', 'dollaroldstyle',
|
||||
'dollarsuperior', 'ampersandsmall', 'Acutesmall', 'parenleftsuperior',
|
||||
'parenrightsuperior', 'twodotenleader', 'onedotenleader', 'comma',
|
||||
'hyphen', 'period', 'fraction', 'zerooldstyle', 'oneoldstyle',
|
||||
'twooldstyle', 'threeoldstyle', 'fouroldstyle', 'fiveoldstyle',
|
||||
'sixoldstyle', 'sevenoldstyle', 'eightoldstyle', 'nineoldstyle',
|
||||
'colon', 'semicolon', 'commasuperior', 'threequartersemdash',
|
||||
'periodsuperior', 'questionsmall', 'asuperior', 'bsuperior',
|
||||
'centsuperior', 'dsuperior', 'esuperior', 'isuperior', 'lsuperior',
|
||||
'msuperior', 'nsuperior', 'osuperior', 'rsuperior', 'ssuperior',
|
||||
'tsuperior', 'ff', 'fi', 'fl', 'ffi', 'ffl', 'parenleftinferior',
|
||||
'parenrightinferior', 'Circumflexsmall', 'hyphensuperior', 'Gravesmall',
|
||||
'Asmall', 'Bsmall', 'Csmall', 'Dsmall', 'Esmall', 'Fsmall', 'Gsmall',
|
||||
'Hsmall', 'Ismall', 'Jsmall', 'Ksmall', 'Lsmall', 'Msmall', 'Nsmall',
|
||||
'Osmall', 'Psmall', 'Qsmall', 'Rsmall', 'Ssmall', 'Tsmall', 'Usmall',
|
||||
'Vsmall', 'Wsmall', 'Xsmall', 'Ysmall', 'Zsmall', 'colonmonetary',
|
||||
'onefitted', 'rupiah', 'Tildesmall', 'exclamdownsmall', 'centoldstyle',
|
||||
'Lslashsmall', 'Scaronsmall', 'Zcaronsmall', 'Dieresissmall',
|
||||
'Brevesmall', 'Caronsmall', 'Dotaccentsmall', 'Macronsmall',
|
||||
'figuredash', 'hypheninferior', 'Ogoneksmall', 'Ringsmall',
|
||||
'Cedillasmall', 'onequarter', 'onehalf', 'threequarters',
|
||||
'questiondownsmall', 'oneeighth', 'threeeighths', 'fiveeighths',
|
||||
'seveneighths', 'onethird', 'twothirds', 'zerosuperior', 'onesuperior',
|
||||
'twosuperior', 'threesuperior', 'foursuperior', 'fivesuperior',
|
||||
'sixsuperior', 'sevensuperior', 'eightsuperior', 'ninesuperior',
|
||||
'zeroinferior', 'oneinferior', 'twoinferior', 'threeinferior',
|
||||
'fourinferior', 'fiveinferior', 'sixinferior', 'seveninferior',
|
||||
'eightinferior', 'nineinferior', 'centinferior', 'dollarinferior',
|
||||
'periodinferior', 'commainferior', 'Agravesmall', 'Aacutesmall',
|
||||
'Acircumflexsmall', 'Atildesmall', 'Adieresissmall', 'Aringsmall',
|
||||
'AEsmall', 'Ccedillasmall', 'Egravesmall', 'Eacutesmall',
|
||||
'Ecircumflexsmall', 'Edieresissmall', 'Igravesmall', 'Iacutesmall',
|
||||
'Icircumflexsmall', 'Idieresissmall', 'Ethsmall', 'Ntildesmall',
|
||||
'Ogravesmall', 'Oacutesmall', 'Ocircumflexsmall', 'Otildesmall',
|
||||
'Odieresissmall', 'OEsmall', 'Oslashsmall', 'Ugravesmall', 'Uacutesmall',
|
||||
'Ucircumflexsmall', 'Udieresissmall', 'Yacutesmall', 'Thornsmall',
|
||||
'Ydieresissmall'
|
||||
".notdef", "space", "exclamsmall", "Hungarumlautsmall", "dollaroldstyle",
|
||||
"dollarsuperior", "ampersandsmall", "Acutesmall", "parenleftsuperior",
|
||||
"parenrightsuperior", "twodotenleader", "onedotenleader", "comma",
|
||||
"hyphen", "period", "fraction", "zerooldstyle", "oneoldstyle",
|
||||
"twooldstyle", "threeoldstyle", "fouroldstyle", "fiveoldstyle",
|
||||
"sixoldstyle", "sevenoldstyle", "eightoldstyle", "nineoldstyle",
|
||||
"colon", "semicolon", "commasuperior", "threequartersemdash",
|
||||
"periodsuperior", "questionsmall", "asuperior", "bsuperior",
|
||||
"centsuperior", "dsuperior", "esuperior", "isuperior", "lsuperior",
|
||||
"msuperior", "nsuperior", "osuperior", "rsuperior", "ssuperior",
|
||||
"tsuperior", "ff", "fi", "fl", "ffi", "ffl", "parenleftinferior",
|
||||
"parenrightinferior", "Circumflexsmall", "hyphensuperior", "Gravesmall",
|
||||
"Asmall", "Bsmall", "Csmall", "Dsmall", "Esmall", "Fsmall", "Gsmall",
|
||||
"Hsmall", "Ismall", "Jsmall", "Ksmall", "Lsmall", "Msmall", "Nsmall",
|
||||
"Osmall", "Psmall", "Qsmall", "Rsmall", "Ssmall", "Tsmall", "Usmall",
|
||||
"Vsmall", "Wsmall", "Xsmall", "Ysmall", "Zsmall", "colonmonetary",
|
||||
"onefitted", "rupiah", "Tildesmall", "exclamdownsmall", "centoldstyle",
|
||||
"Lslashsmall", "Scaronsmall", "Zcaronsmall", "Dieresissmall",
|
||||
"Brevesmall", "Caronsmall", "Dotaccentsmall", "Macronsmall",
|
||||
"figuredash", "hypheninferior", "Ogoneksmall", "Ringsmall",
|
||||
"Cedillasmall", "onequarter", "onehalf", "threequarters",
|
||||
"questiondownsmall", "oneeighth", "threeeighths", "fiveeighths",
|
||||
"seveneighths", "onethird", "twothirds", "zerosuperior", "onesuperior",
|
||||
"twosuperior", "threesuperior", "foursuperior", "fivesuperior",
|
||||
"sixsuperior", "sevensuperior", "eightsuperior", "ninesuperior",
|
||||
"zeroinferior", "oneinferior", "twoinferior", "threeinferior",
|
||||
"fourinferior", "fiveinferior", "sixinferior", "seveninferior",
|
||||
"eightinferior", "nineinferior", "centinferior", "dollarinferior",
|
||||
"periodinferior", "commainferior", "Agravesmall", "Aacutesmall",
|
||||
"Acircumflexsmall", "Atildesmall", "Adieresissmall", "Aringsmall",
|
||||
"AEsmall", "Ccedillasmall", "Egravesmall", "Eacutesmall",
|
||||
"Ecircumflexsmall", "Edieresissmall", "Igravesmall", "Iacutesmall",
|
||||
"Icircumflexsmall", "Idieresissmall", "Ethsmall", "Ntildesmall",
|
||||
"Ogravesmall", "Oacutesmall", "Ocircumflexsmall", "Otildesmall",
|
||||
"Odieresissmall", "OEsmall", "Oslashsmall", "Ugravesmall", "Uacutesmall",
|
||||
"Ucircumflexsmall", "Udieresissmall", "Yacutesmall", "Thornsmall",
|
||||
"Ydieresissmall"
|
||||
];
|
||||
|
||||
// prettier-ignore
|
||||
const ExpertSubsetCharset = [
|
||||
'.notdef', 'space', 'dollaroldstyle', 'dollarsuperior',
|
||||
'parenleftsuperior', 'parenrightsuperior', 'twodotenleader',
|
||||
'onedotenleader', 'comma', 'hyphen', 'period', 'fraction',
|
||||
'zerooldstyle', 'oneoldstyle', 'twooldstyle', 'threeoldstyle',
|
||||
'fouroldstyle', 'fiveoldstyle', 'sixoldstyle', 'sevenoldstyle',
|
||||
'eightoldstyle', 'nineoldstyle', 'colon', 'semicolon', 'commasuperior',
|
||||
'threequartersemdash', 'periodsuperior', 'asuperior', 'bsuperior',
|
||||
'centsuperior', 'dsuperior', 'esuperior', 'isuperior', 'lsuperior',
|
||||
'msuperior', 'nsuperior', 'osuperior', 'rsuperior', 'ssuperior',
|
||||
'tsuperior', 'ff', 'fi', 'fl', 'ffi', 'ffl', 'parenleftinferior',
|
||||
'parenrightinferior', 'hyphensuperior', 'colonmonetary', 'onefitted',
|
||||
'rupiah', 'centoldstyle', 'figuredash', 'hypheninferior', 'onequarter',
|
||||
'onehalf', 'threequarters', 'oneeighth', 'threeeighths', 'fiveeighths',
|
||||
'seveneighths', 'onethird', 'twothirds', 'zerosuperior', 'onesuperior',
|
||||
'twosuperior', 'threesuperior', 'foursuperior', 'fivesuperior',
|
||||
'sixsuperior', 'sevensuperior', 'eightsuperior', 'ninesuperior',
|
||||
'zeroinferior', 'oneinferior', 'twoinferior', 'threeinferior',
|
||||
'fourinferior', 'fiveinferior', 'sixinferior', 'seveninferior',
|
||||
'eightinferior', 'nineinferior', 'centinferior', 'dollarinferior',
|
||||
'periodinferior', 'commainferior'
|
||||
".notdef", "space", "dollaroldstyle", "dollarsuperior",
|
||||
"parenleftsuperior", "parenrightsuperior", "twodotenleader",
|
||||
"onedotenleader", "comma", "hyphen", "period", "fraction",
|
||||
"zerooldstyle", "oneoldstyle", "twooldstyle", "threeoldstyle",
|
||||
"fouroldstyle", "fiveoldstyle", "sixoldstyle", "sevenoldstyle",
|
||||
"eightoldstyle", "nineoldstyle", "colon", "semicolon", "commasuperior",
|
||||
"threequartersemdash", "periodsuperior", "asuperior", "bsuperior",
|
||||
"centsuperior", "dsuperior", "esuperior", "isuperior", "lsuperior",
|
||||
"msuperior", "nsuperior", "osuperior", "rsuperior", "ssuperior",
|
||||
"tsuperior", "ff", "fi", "fl", "ffi", "ffl", "parenleftinferior",
|
||||
"parenrightinferior", "hyphensuperior", "colonmonetary", "onefitted",
|
||||
"rupiah", "centoldstyle", "figuredash", "hypheninferior", "onequarter",
|
||||
"onehalf", "threequarters", "oneeighth", "threeeighths", "fiveeighths",
|
||||
"seveneighths", "onethird", "twothirds", "zerosuperior", "onesuperior",
|
||||
"twosuperior", "threesuperior", "foursuperior", "fivesuperior",
|
||||
"sixsuperior", "sevensuperior", "eightsuperior", "ninesuperior",
|
||||
"zeroinferior", "oneinferior", "twoinferior", "threeinferior",
|
||||
"fourinferior", "fiveinferior", "sixinferior", "seveninferior",
|
||||
"eightinferior", "nineinferior", "centinferior", "dollarinferior",
|
||||
"periodinferior", "commainferior"
|
||||
];
|
||||
|
||||
export {
|
||||
ISOAdobeCharset,
|
||||
ExpertCharset,
|
||||
ExpertSubsetCharset,
|
||||
};
|
||||
export { ISOAdobeCharset, ExpertCharset, ExpertSubsetCharset };
|
||||
|
@ -15,9 +15,12 @@
|
||||
/* eslint no-var: error */
|
||||
|
||||
import {
|
||||
arrayByteLength, arraysToBytes, createPromiseCapability, isEmptyObj
|
||||
} from '../shared/util';
|
||||
import { MissingDataException } from './core_utils';
|
||||
arrayByteLength,
|
||||
arraysToBytes,
|
||||
createPromiseCapability,
|
||||
isEmptyObj,
|
||||
} from "../shared/util";
|
||||
import { MissingDataException } from "./core_utils";
|
||||
|
||||
class ChunkedStream {
|
||||
constructor(length, chunkSize, manager) {
|
||||
@ -86,8 +89,10 @@ class ChunkedStream {
|
||||
this.bytes.set(new Uint8Array(data), position);
|
||||
position += data.byteLength;
|
||||
this.progressiveDataLength = position;
|
||||
const endChunk = position >= this.end ? this.numChunks :
|
||||
Math.floor(position / this.chunkSize);
|
||||
const endChunk =
|
||||
position >= this.end
|
||||
? this.numChunks
|
||||
: Math.floor(position / this.chunkSize);
|
||||
|
||||
for (let curChunk = beginChunk; curChunk < endChunk; ++curChunk) {
|
||||
if (!this.loadedChunks[curChunk]) {
|
||||
@ -194,7 +199,7 @@ class ChunkedStream {
|
||||
}
|
||||
const subarray = bytes.subarray(pos, strEnd);
|
||||
// `this.bytes` is always a `Uint8Array` here.
|
||||
return (forceClamped ? new Uint8ClampedArray(subarray) : subarray);
|
||||
return forceClamped ? new Uint8ClampedArray(subarray) : subarray;
|
||||
}
|
||||
|
||||
let end = pos + length;
|
||||
@ -208,7 +213,7 @@ class ChunkedStream {
|
||||
this.pos = end;
|
||||
const subarray = bytes.subarray(pos, end);
|
||||
// `this.bytes` is always a `Uint8Array` here.
|
||||
return (forceClamped ? new Uint8ClampedArray(subarray) : subarray);
|
||||
return forceClamped ? new Uint8ClampedArray(subarray) : subarray;
|
||||
}
|
||||
|
||||
peekByte() {
|
||||
@ -332,16 +337,17 @@ class ChunkedStreamManager {
|
||||
rangeReader.onProgress = this.onProgress.bind(this);
|
||||
}
|
||||
|
||||
let chunks = [], loaded = 0;
|
||||
let chunks = [],
|
||||
loaded = 0;
|
||||
const promise = new Promise((resolve, reject) => {
|
||||
const readChunk = (chunk) => {
|
||||
const readChunk = chunk => {
|
||||
try {
|
||||
if (!chunk.done) {
|
||||
const data = chunk.value;
|
||||
chunks.push(data);
|
||||
loaded += arrayByteLength(data);
|
||||
if (rangeReader.isStreamingSupported) {
|
||||
this.onProgress({ loaded, });
|
||||
this.onProgress({ loaded });
|
||||
}
|
||||
rangeReader.read().then(readChunk, reject);
|
||||
return;
|
||||
@ -355,11 +361,11 @@ class ChunkedStreamManager {
|
||||
};
|
||||
rangeReader.read().then(readChunk, reject);
|
||||
});
|
||||
promise.then((data) => {
|
||||
promise.then(data => {
|
||||
if (this.aborted) {
|
||||
return; // Ignoring any data after abort.
|
||||
}
|
||||
this.onReceiveData({ chunk: data, begin, });
|
||||
this.onReceiveData({ chunk: data, begin });
|
||||
});
|
||||
// TODO check errors
|
||||
}
|
||||
@ -470,13 +476,11 @@ class ChunkedStreamManager {
|
||||
}
|
||||
|
||||
if (prevChunk >= 0 && prevChunk + 1 !== chunk) {
|
||||
groupedChunks.push({ beginChunk,
|
||||
endChunk: prevChunk + 1, });
|
||||
groupedChunks.push({ beginChunk, endChunk: prevChunk + 1 });
|
||||
beginChunk = chunk;
|
||||
}
|
||||
if (i + 1 === chunks.length) {
|
||||
groupedChunks.push({ beginChunk,
|
||||
endChunk: chunk + 1, });
|
||||
groupedChunks.push({ beginChunk, endChunk: chunk + 1 });
|
||||
}
|
||||
|
||||
prevChunk = chunk;
|
||||
@ -485,7 +489,7 @@ class ChunkedStreamManager {
|
||||
}
|
||||
|
||||
onProgress(args) {
|
||||
this.msgHandler.send('DocProgress', {
|
||||
this.msgHandler.send("DocProgress", {
|
||||
loaded: this.stream.numChunksLoaded * this.chunkSize + args.loaded,
|
||||
total: this.length,
|
||||
});
|
||||
@ -498,8 +502,10 @@ class ChunkedStreamManager {
|
||||
const end = begin + chunk.byteLength;
|
||||
|
||||
const beginChunk = Math.floor(begin / this.chunkSize);
|
||||
const endChunk = end < this.length ? Math.floor(end / this.chunkSize) :
|
||||
Math.ceil(end / this.chunkSize);
|
||||
const endChunk =
|
||||
end < this.length
|
||||
? Math.floor(end / this.chunkSize)
|
||||
: Math.ceil(end / this.chunkSize);
|
||||
|
||||
if (isProgressive) {
|
||||
this.stream.onReceiveProgressiveData(chunk);
|
||||
@ -557,7 +563,7 @@ class ChunkedStreamManager {
|
||||
capability.resolve();
|
||||
}
|
||||
|
||||
this.msgHandler.send('DocProgress', {
|
||||
this.msgHandler.send("DocProgress", {
|
||||
loaded: this.stream.numChunksLoaded * this.chunkSize,
|
||||
total: this.length,
|
||||
});
|
||||
@ -586,7 +592,4 @@ class ChunkedStreamManager {
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
ChunkedStream,
|
||||
ChunkedStreamManager,
|
||||
};
|
||||
export { ChunkedStream, ChunkedStreamManager };
|
||||
|
562
src/core/cmap.js
562
src/core/cmap.js
@ -14,184 +14,189 @@
|
||||
*/
|
||||
|
||||
import {
|
||||
CMapCompressionType, FormatError, isString, unreachable, warn
|
||||
} from '../shared/util';
|
||||
import { isCmd, isEOF, isName, isStream } from './primitives';
|
||||
import { Lexer } from './parser';
|
||||
import { MissingDataException } from './core_utils';
|
||||
import { Stream } from './stream';
|
||||
CMapCompressionType,
|
||||
FormatError,
|
||||
isString,
|
||||
unreachable,
|
||||
warn,
|
||||
} from "../shared/util";
|
||||
import { isCmd, isEOF, isName, isStream } from "./primitives";
|
||||
import { Lexer } from "./parser";
|
||||
import { MissingDataException } from "./core_utils";
|
||||
import { Stream } from "./stream";
|
||||
|
||||
var BUILT_IN_CMAPS = [
|
||||
// << Start unicode maps.
|
||||
'Adobe-GB1-UCS2',
|
||||
'Adobe-CNS1-UCS2',
|
||||
'Adobe-Japan1-UCS2',
|
||||
'Adobe-Korea1-UCS2',
|
||||
// >> End unicode maps.
|
||||
'78-EUC-H',
|
||||
'78-EUC-V',
|
||||
'78-H',
|
||||
'78-RKSJ-H',
|
||||
'78-RKSJ-V',
|
||||
'78-V',
|
||||
'78ms-RKSJ-H',
|
||||
'78ms-RKSJ-V',
|
||||
'83pv-RKSJ-H',
|
||||
'90ms-RKSJ-H',
|
||||
'90ms-RKSJ-V',
|
||||
'90msp-RKSJ-H',
|
||||
'90msp-RKSJ-V',
|
||||
'90pv-RKSJ-H',
|
||||
'90pv-RKSJ-V',
|
||||
'Add-H',
|
||||
'Add-RKSJ-H',
|
||||
'Add-RKSJ-V',
|
||||
'Add-V',
|
||||
'Adobe-CNS1-0',
|
||||
'Adobe-CNS1-1',
|
||||
'Adobe-CNS1-2',
|
||||
'Adobe-CNS1-3',
|
||||
'Adobe-CNS1-4',
|
||||
'Adobe-CNS1-5',
|
||||
'Adobe-CNS1-6',
|
||||
'Adobe-GB1-0',
|
||||
'Adobe-GB1-1',
|
||||
'Adobe-GB1-2',
|
||||
'Adobe-GB1-3',
|
||||
'Adobe-GB1-4',
|
||||
'Adobe-GB1-5',
|
||||
'Adobe-Japan1-0',
|
||||
'Adobe-Japan1-1',
|
||||
'Adobe-Japan1-2',
|
||||
'Adobe-Japan1-3',
|
||||
'Adobe-Japan1-4',
|
||||
'Adobe-Japan1-5',
|
||||
'Adobe-Japan1-6',
|
||||
'Adobe-Korea1-0',
|
||||
'Adobe-Korea1-1',
|
||||
'Adobe-Korea1-2',
|
||||
'B5-H',
|
||||
'B5-V',
|
||||
'B5pc-H',
|
||||
'B5pc-V',
|
||||
'CNS-EUC-H',
|
||||
'CNS-EUC-V',
|
||||
'CNS1-H',
|
||||
'CNS1-V',
|
||||
'CNS2-H',
|
||||
'CNS2-V',
|
||||
'ETHK-B5-H',
|
||||
'ETHK-B5-V',
|
||||
'ETen-B5-H',
|
||||
'ETen-B5-V',
|
||||
'ETenms-B5-H',
|
||||
'ETenms-B5-V',
|
||||
'EUC-H',
|
||||
'EUC-V',
|
||||
'Ext-H',
|
||||
'Ext-RKSJ-H',
|
||||
'Ext-RKSJ-V',
|
||||
'Ext-V',
|
||||
'GB-EUC-H',
|
||||
'GB-EUC-V',
|
||||
'GB-H',
|
||||
'GB-V',
|
||||
'GBK-EUC-H',
|
||||
'GBK-EUC-V',
|
||||
'GBK2K-H',
|
||||
'GBK2K-V',
|
||||
'GBKp-EUC-H',
|
||||
'GBKp-EUC-V',
|
||||
'GBT-EUC-H',
|
||||
'GBT-EUC-V',
|
||||
'GBT-H',
|
||||
'GBT-V',
|
||||
'GBTpc-EUC-H',
|
||||
'GBTpc-EUC-V',
|
||||
'GBpc-EUC-H',
|
||||
'GBpc-EUC-V',
|
||||
'H',
|
||||
'HKdla-B5-H',
|
||||
'HKdla-B5-V',
|
||||
'HKdlb-B5-H',
|
||||
'HKdlb-B5-V',
|
||||
'HKgccs-B5-H',
|
||||
'HKgccs-B5-V',
|
||||
'HKm314-B5-H',
|
||||
'HKm314-B5-V',
|
||||
'HKm471-B5-H',
|
||||
'HKm471-B5-V',
|
||||
'HKscs-B5-H',
|
||||
'HKscs-B5-V',
|
||||
'Hankaku',
|
||||
'Hiragana',
|
||||
'KSC-EUC-H',
|
||||
'KSC-EUC-V',
|
||||
'KSC-H',
|
||||
'KSC-Johab-H',
|
||||
'KSC-Johab-V',
|
||||
'KSC-V',
|
||||
'KSCms-UHC-H',
|
||||
'KSCms-UHC-HW-H',
|
||||
'KSCms-UHC-HW-V',
|
||||
'KSCms-UHC-V',
|
||||
'KSCpc-EUC-H',
|
||||
'KSCpc-EUC-V',
|
||||
'Katakana',
|
||||
'NWP-H',
|
||||
'NWP-V',
|
||||
'RKSJ-H',
|
||||
'RKSJ-V',
|
||||
'Roman',
|
||||
'UniCNS-UCS2-H',
|
||||
'UniCNS-UCS2-V',
|
||||
'UniCNS-UTF16-H',
|
||||
'UniCNS-UTF16-V',
|
||||
'UniCNS-UTF32-H',
|
||||
'UniCNS-UTF32-V',
|
||||
'UniCNS-UTF8-H',
|
||||
'UniCNS-UTF8-V',
|
||||
'UniGB-UCS2-H',
|
||||
'UniGB-UCS2-V',
|
||||
'UniGB-UTF16-H',
|
||||
'UniGB-UTF16-V',
|
||||
'UniGB-UTF32-H',
|
||||
'UniGB-UTF32-V',
|
||||
'UniGB-UTF8-H',
|
||||
'UniGB-UTF8-V',
|
||||
'UniJIS-UCS2-H',
|
||||
'UniJIS-UCS2-HW-H',
|
||||
'UniJIS-UCS2-HW-V',
|
||||
'UniJIS-UCS2-V',
|
||||
'UniJIS-UTF16-H',
|
||||
'UniJIS-UTF16-V',
|
||||
'UniJIS-UTF32-H',
|
||||
'UniJIS-UTF32-V',
|
||||
'UniJIS-UTF8-H',
|
||||
'UniJIS-UTF8-V',
|
||||
'UniJIS2004-UTF16-H',
|
||||
'UniJIS2004-UTF16-V',
|
||||
'UniJIS2004-UTF32-H',
|
||||
'UniJIS2004-UTF32-V',
|
||||
'UniJIS2004-UTF8-H',
|
||||
'UniJIS2004-UTF8-V',
|
||||
'UniJISPro-UCS2-HW-V',
|
||||
'UniJISPro-UCS2-V',
|
||||
'UniJISPro-UTF8-V',
|
||||
'UniJISX0213-UTF32-H',
|
||||
'UniJISX0213-UTF32-V',
|
||||
'UniJISX02132004-UTF32-H',
|
||||
'UniJISX02132004-UTF32-V',
|
||||
'UniKS-UCS2-H',
|
||||
'UniKS-UCS2-V',
|
||||
'UniKS-UTF16-H',
|
||||
'UniKS-UTF16-V',
|
||||
'UniKS-UTF32-H',
|
||||
'UniKS-UTF32-V',
|
||||
'UniKS-UTF8-H',
|
||||
'UniKS-UTF8-V',
|
||||
'V',
|
||||
'WP-Symbol'];
|
||||
// << Start unicode maps.
|
||||
"Adobe-GB1-UCS2",
|
||||
"Adobe-CNS1-UCS2",
|
||||
"Adobe-Japan1-UCS2",
|
||||
"Adobe-Korea1-UCS2",
|
||||
// >> End unicode maps.
|
||||
"78-EUC-H",
|
||||
"78-EUC-V",
|
||||
"78-H",
|
||||
"78-RKSJ-H",
|
||||
"78-RKSJ-V",
|
||||
"78-V",
|
||||
"78ms-RKSJ-H",
|
||||
"78ms-RKSJ-V",
|
||||
"83pv-RKSJ-H",
|
||||
"90ms-RKSJ-H",
|
||||
"90ms-RKSJ-V",
|
||||
"90msp-RKSJ-H",
|
||||
"90msp-RKSJ-V",
|
||||
"90pv-RKSJ-H",
|
||||
"90pv-RKSJ-V",
|
||||
"Add-H",
|
||||
"Add-RKSJ-H",
|
||||
"Add-RKSJ-V",
|
||||
"Add-V",
|
||||
"Adobe-CNS1-0",
|
||||
"Adobe-CNS1-1",
|
||||
"Adobe-CNS1-2",
|
||||
"Adobe-CNS1-3",
|
||||
"Adobe-CNS1-4",
|
||||
"Adobe-CNS1-5",
|
||||
"Adobe-CNS1-6",
|
||||
"Adobe-GB1-0",
|
||||
"Adobe-GB1-1",
|
||||
"Adobe-GB1-2",
|
||||
"Adobe-GB1-3",
|
||||
"Adobe-GB1-4",
|
||||
"Adobe-GB1-5",
|
||||
"Adobe-Japan1-0",
|
||||
"Adobe-Japan1-1",
|
||||
"Adobe-Japan1-2",
|
||||
"Adobe-Japan1-3",
|
||||
"Adobe-Japan1-4",
|
||||
"Adobe-Japan1-5",
|
||||
"Adobe-Japan1-6",
|
||||
"Adobe-Korea1-0",
|
||||
"Adobe-Korea1-1",
|
||||
"Adobe-Korea1-2",
|
||||
"B5-H",
|
||||
"B5-V",
|
||||
"B5pc-H",
|
||||
"B5pc-V",
|
||||
"CNS-EUC-H",
|
||||
"CNS-EUC-V",
|
||||
"CNS1-H",
|
||||
"CNS1-V",
|
||||
"CNS2-H",
|
||||
"CNS2-V",
|
||||
"ETHK-B5-H",
|
||||
"ETHK-B5-V",
|
||||
"ETen-B5-H",
|
||||
"ETen-B5-V",
|
||||
"ETenms-B5-H",
|
||||
"ETenms-B5-V",
|
||||
"EUC-H",
|
||||
"EUC-V",
|
||||
"Ext-H",
|
||||
"Ext-RKSJ-H",
|
||||
"Ext-RKSJ-V",
|
||||
"Ext-V",
|
||||
"GB-EUC-H",
|
||||
"GB-EUC-V",
|
||||
"GB-H",
|
||||
"GB-V",
|
||||
"GBK-EUC-H",
|
||||
"GBK-EUC-V",
|
||||
"GBK2K-H",
|
||||
"GBK2K-V",
|
||||
"GBKp-EUC-H",
|
||||
"GBKp-EUC-V",
|
||||
"GBT-EUC-H",
|
||||
"GBT-EUC-V",
|
||||
"GBT-H",
|
||||
"GBT-V",
|
||||
"GBTpc-EUC-H",
|
||||
"GBTpc-EUC-V",
|
||||
"GBpc-EUC-H",
|
||||
"GBpc-EUC-V",
|
||||
"H",
|
||||
"HKdla-B5-H",
|
||||
"HKdla-B5-V",
|
||||
"HKdlb-B5-H",
|
||||
"HKdlb-B5-V",
|
||||
"HKgccs-B5-H",
|
||||
"HKgccs-B5-V",
|
||||
"HKm314-B5-H",
|
||||
"HKm314-B5-V",
|
||||
"HKm471-B5-H",
|
||||
"HKm471-B5-V",
|
||||
"HKscs-B5-H",
|
||||
"HKscs-B5-V",
|
||||
"Hankaku",
|
||||
"Hiragana",
|
||||
"KSC-EUC-H",
|
||||
"KSC-EUC-V",
|
||||
"KSC-H",
|
||||
"KSC-Johab-H",
|
||||
"KSC-Johab-V",
|
||||
"KSC-V",
|
||||
"KSCms-UHC-H",
|
||||
"KSCms-UHC-HW-H",
|
||||
"KSCms-UHC-HW-V",
|
||||
"KSCms-UHC-V",
|
||||
"KSCpc-EUC-H",
|
||||
"KSCpc-EUC-V",
|
||||
"Katakana",
|
||||
"NWP-H",
|
||||
"NWP-V",
|
||||
"RKSJ-H",
|
||||
"RKSJ-V",
|
||||
"Roman",
|
||||
"UniCNS-UCS2-H",
|
||||
"UniCNS-UCS2-V",
|
||||
"UniCNS-UTF16-H",
|
||||
"UniCNS-UTF16-V",
|
||||
"UniCNS-UTF32-H",
|
||||
"UniCNS-UTF32-V",
|
||||
"UniCNS-UTF8-H",
|
||||
"UniCNS-UTF8-V",
|
||||
"UniGB-UCS2-H",
|
||||
"UniGB-UCS2-V",
|
||||
"UniGB-UTF16-H",
|
||||
"UniGB-UTF16-V",
|
||||
"UniGB-UTF32-H",
|
||||
"UniGB-UTF32-V",
|
||||
"UniGB-UTF8-H",
|
||||
"UniGB-UTF8-V",
|
||||
"UniJIS-UCS2-H",
|
||||
"UniJIS-UCS2-HW-H",
|
||||
"UniJIS-UCS2-HW-V",
|
||||
"UniJIS-UCS2-V",
|
||||
"UniJIS-UTF16-H",
|
||||
"UniJIS-UTF16-V",
|
||||
"UniJIS-UTF32-H",
|
||||
"UniJIS-UTF32-V",
|
||||
"UniJIS-UTF8-H",
|
||||
"UniJIS-UTF8-V",
|
||||
"UniJIS2004-UTF16-H",
|
||||
"UniJIS2004-UTF16-V",
|
||||
"UniJIS2004-UTF32-H",
|
||||
"UniJIS2004-UTF32-V",
|
||||
"UniJIS2004-UTF8-H",
|
||||
"UniJIS2004-UTF8-V",
|
||||
"UniJISPro-UCS2-HW-V",
|
||||
"UniJISPro-UCS2-V",
|
||||
"UniJISPro-UTF8-V",
|
||||
"UniJISX0213-UTF32-H",
|
||||
"UniJISX0213-UTF32-V",
|
||||
"UniJISX02132004-UTF32-H",
|
||||
"UniJISX02132004-UTF32-V",
|
||||
"UniKS-UCS2-H",
|
||||
"UniKS-UCS2-V",
|
||||
"UniKS-UTF16-H",
|
||||
"UniKS-UTF16-V",
|
||||
"UniKS-UTF32-H",
|
||||
"UniKS-UTF32-V",
|
||||
"UniKS-UTF8-H",
|
||||
"UniKS-UTF8-V",
|
||||
"V",
|
||||
"WP-Symbol",
|
||||
];
|
||||
|
||||
// CMap, not to be confused with TrueType's cmap.
|
||||
class CMap {
|
||||
@ -206,7 +211,7 @@ class CMap {
|
||||
// - bf chars are variable-length byte sequences, stored as strings, with
|
||||
// one byte per character.
|
||||
this._map = [];
|
||||
this.name = '';
|
||||
this.name = "";
|
||||
this.vertical = false;
|
||||
this.useCMap = null;
|
||||
this.builtInCMap = builtInCMap;
|
||||
@ -228,13 +233,15 @@ class CMap {
|
||||
while (low <= high) {
|
||||
this._map[low++] = dstLow;
|
||||
// Only the last byte has to be incremented.
|
||||
dstLow = dstLow.substring(0, lastByte) +
|
||||
String.fromCharCode(dstLow.charCodeAt(lastByte) + 1);
|
||||
dstLow =
|
||||
dstLow.substring(0, lastByte) +
|
||||
String.fromCharCode(dstLow.charCodeAt(lastByte) + 1);
|
||||
}
|
||||
}
|
||||
|
||||
mapBfRangeToArray(low, high, array) {
|
||||
let i = 0, ii = array.length;
|
||||
let i = 0,
|
||||
ii = array.length;
|
||||
while (low <= high && i < ii) {
|
||||
this._map[low] = array[i++];
|
||||
++low;
|
||||
@ -284,7 +291,7 @@ class CMap {
|
||||
}
|
||||
for (let charCode in map) {
|
||||
if (map[charCode] === value) {
|
||||
return (charCode | 0);
|
||||
return charCode | 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
@ -303,7 +310,7 @@ class CMap {
|
||||
c = ((c << 8) | str.charCodeAt(offset + n)) >>> 0;
|
||||
// Check each codespace range to see if it falls within.
|
||||
const codespaceRange = codespaceRanges[n];
|
||||
for (let k = 0, kk = codespaceRange.length; k < kk;) {
|
||||
for (let k = 0, kk = codespaceRange.length; k < kk; ) {
|
||||
const low = codespaceRange[k++];
|
||||
const high = codespaceRange[k++];
|
||||
if (c >= low && c <= high) {
|
||||
@ -322,7 +329,7 @@ class CMap {
|
||||
}
|
||||
|
||||
get isIdentityCMap() {
|
||||
if (!(this.name === 'Identity-H' || this.name === 'Identity-V')) {
|
||||
if (!(this.name === "Identity-H" || this.name === "Identity-V")) {
|
||||
return false;
|
||||
}
|
||||
if (this._map.length !== 0x10000) {
|
||||
@ -348,23 +355,23 @@ class IdentityCMap extends CMap {
|
||||
}
|
||||
|
||||
mapCidRange(low, high, dstLow) {
|
||||
unreachable('should not call mapCidRange');
|
||||
unreachable("should not call mapCidRange");
|
||||
}
|
||||
|
||||
mapBfRange(low, high, dstLow) {
|
||||
unreachable('should not call mapBfRange');
|
||||
unreachable("should not call mapBfRange");
|
||||
}
|
||||
|
||||
mapBfRangeToArray(low, high, array) {
|
||||
unreachable('should not call mapBfRangeToArray');
|
||||
unreachable("should not call mapBfRangeToArray");
|
||||
}
|
||||
|
||||
mapOne(src, dst) {
|
||||
unreachable('should not call mapCidOne');
|
||||
unreachable("should not call mapCidOne");
|
||||
}
|
||||
|
||||
lookup(code) {
|
||||
return (Number.isInteger(code) && code <= 0xffff) ? code : undefined;
|
||||
return Number.isInteger(code) && code <= 0xffff ? code : undefined;
|
||||
}
|
||||
|
||||
contains(code) {
|
||||
@ -378,7 +385,7 @@ class IdentityCMap extends CMap {
|
||||
}
|
||||
|
||||
charCodeOf(value) {
|
||||
return (Number.isInteger(value) && value <= 0xffff) ? value : -1;
|
||||
return Number.isInteger(value) && value <= 0xffff ? value : -1;
|
||||
}
|
||||
|
||||
getMap() {
|
||||
@ -394,8 +401,9 @@ class IdentityCMap extends CMap {
|
||||
return 0x10000;
|
||||
}
|
||||
|
||||
get isIdentityCMap() { // eslint-disable-line getter-return
|
||||
unreachable('should not access .isIdentityCMap');
|
||||
// eslint-disable-next-line getter-return
|
||||
get isIdentityCMap() {
|
||||
unreachable("should not access .isIdentityCMap");
|
||||
}
|
||||
}
|
||||
|
||||
@ -461,34 +469,36 @@ var BinaryCMapReader = (function BinaryCMapReaderClosure() {
|
||||
do {
|
||||
var b = this.readByte();
|
||||
if (b < 0) {
|
||||
throw new FormatError('unexpected EOF in bcmap');
|
||||
throw new FormatError("unexpected EOF in bcmap");
|
||||
}
|
||||
last = !(b & 0x80);
|
||||
n = (n << 7) | (b & 0x7F);
|
||||
n = (n << 7) | (b & 0x7f);
|
||||
} while (!last);
|
||||
return n;
|
||||
},
|
||||
readSigned() {
|
||||
var n = this.readNumber();
|
||||
return (n & 1) ? ~(n >>> 1) : n >>> 1;
|
||||
return n & 1 ? ~(n >>> 1) : n >>> 1;
|
||||
},
|
||||
readHex(num, size) {
|
||||
num.set(this.buffer.subarray(this.pos,
|
||||
this.pos + size + 1));
|
||||
num.set(this.buffer.subarray(this.pos, this.pos + size + 1));
|
||||
this.pos += size + 1;
|
||||
},
|
||||
readHexNumber(num, size) {
|
||||
var last;
|
||||
var stack = this.tmpBuf, sp = 0;
|
||||
var stack = this.tmpBuf,
|
||||
sp = 0;
|
||||
do {
|
||||
var b = this.readByte();
|
||||
if (b < 0) {
|
||||
throw new FormatError('unexpected EOF in bcmap');
|
||||
throw new FormatError("unexpected EOF in bcmap");
|
||||
}
|
||||
last = !(b & 0x80);
|
||||
stack[sp++] = b & 0x7F;
|
||||
stack[sp++] = b & 0x7f;
|
||||
} while (!last);
|
||||
var i = size, buffer = 0, bufferSize = 0;
|
||||
var i = size,
|
||||
buffer = 0,
|
||||
bufferSize = 0;
|
||||
while (i >= 0) {
|
||||
while (bufferSize < 8 && stack.length > 0) {
|
||||
buffer = (stack[--sp] << bufferSize) | buffer;
|
||||
@ -511,7 +521,7 @@ var BinaryCMapReader = (function BinaryCMapReaderClosure() {
|
||||
},
|
||||
readString() {
|
||||
var len = this.readNumber();
|
||||
var s = '';
|
||||
var s = "";
|
||||
for (var i = 0; i < len; i++) {
|
||||
s += String.fromCharCode(this.readNumber());
|
||||
}
|
||||
@ -520,7 +530,7 @@ var BinaryCMapReader = (function BinaryCMapReaderClosure() {
|
||||
};
|
||||
|
||||
function processBinaryCMap(data, cMap, extend) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var stream = new BinaryCMapStream(data);
|
||||
var header = stream.readByte();
|
||||
cMap.vertical = !!(header & 1);
|
||||
@ -536,8 +546,9 @@ var BinaryCMapReader = (function BinaryCMapReaderClosure() {
|
||||
var b;
|
||||
while ((b = stream.readByte()) >= 0) {
|
||||
var type = b >> 5;
|
||||
if (type === 7) { // metadata, e.g. comment or usecmap
|
||||
switch (b & 0x1F) {
|
||||
if (type === 7) {
|
||||
// metadata, e.g. comment or usecmap
|
||||
switch (b & 0x1f) {
|
||||
case 0:
|
||||
stream.readString(); // skipping comment
|
||||
break;
|
||||
@ -551,7 +562,7 @@ var BinaryCMapReader = (function BinaryCMapReaderClosure() {
|
||||
var dataSize = b & 15;
|
||||
|
||||
if (dataSize + 1 > MAX_NUM_SIZE) {
|
||||
throw new Error('processBinaryCMap: Invalid dataSize.');
|
||||
throw new Error("processBinaryCMap: Invalid dataSize.");
|
||||
}
|
||||
|
||||
var ucs2DataSize = 1;
|
||||
@ -562,16 +573,22 @@ var BinaryCMapReader = (function BinaryCMapReaderClosure() {
|
||||
stream.readHex(start, dataSize);
|
||||
stream.readHexNumber(end, dataSize);
|
||||
addHex(end, start, dataSize);
|
||||
cMap.addCodespaceRange(dataSize + 1, hexToInt(start, dataSize),
|
||||
hexToInt(end, dataSize));
|
||||
cMap.addCodespaceRange(
|
||||
dataSize + 1,
|
||||
hexToInt(start, dataSize),
|
||||
hexToInt(end, dataSize)
|
||||
);
|
||||
for (i = 1; i < subitemsCount; i++) {
|
||||
incHex(end, dataSize);
|
||||
stream.readHexNumber(start, dataSize);
|
||||
addHex(start, end, dataSize);
|
||||
stream.readHexNumber(end, dataSize);
|
||||
addHex(end, start, dataSize);
|
||||
cMap.addCodespaceRange(dataSize + 1, hexToInt(start, dataSize),
|
||||
hexToInt(end, dataSize));
|
||||
cMap.addCodespaceRange(
|
||||
dataSize + 1,
|
||||
hexToInt(start, dataSize),
|
||||
hexToInt(end, dataSize)
|
||||
);
|
||||
}
|
||||
break;
|
||||
case 1: // notdefrange
|
||||
@ -609,8 +626,11 @@ var BinaryCMapReader = (function BinaryCMapReaderClosure() {
|
||||
stream.readHexNumber(end, dataSize);
|
||||
addHex(end, start, dataSize);
|
||||
code = stream.readNumber();
|
||||
cMap.mapCidRange(hexToInt(start, dataSize), hexToInt(end, dataSize),
|
||||
code);
|
||||
cMap.mapCidRange(
|
||||
hexToInt(start, dataSize),
|
||||
hexToInt(end, dataSize),
|
||||
code
|
||||
);
|
||||
for (i = 1; i < subitemsCount; i++) {
|
||||
incHex(end, dataSize);
|
||||
if (!sequence) {
|
||||
@ -622,15 +642,20 @@ var BinaryCMapReader = (function BinaryCMapReaderClosure() {
|
||||
stream.readHexNumber(end, dataSize);
|
||||
addHex(end, start, dataSize);
|
||||
code = stream.readNumber();
|
||||
cMap.mapCidRange(hexToInt(start, dataSize),
|
||||
hexToInt(end, dataSize), code);
|
||||
cMap.mapCidRange(
|
||||
hexToInt(start, dataSize),
|
||||
hexToInt(end, dataSize),
|
||||
code
|
||||
);
|
||||
}
|
||||
break;
|
||||
case 4: // bfchar
|
||||
stream.readHex(char, ucs2DataSize);
|
||||
stream.readHex(charCode, dataSize);
|
||||
cMap.mapOne(hexToInt(char, ucs2DataSize),
|
||||
hexToStr(charCode, dataSize));
|
||||
cMap.mapOne(
|
||||
hexToInt(char, ucs2DataSize),
|
||||
hexToStr(charCode, dataSize)
|
||||
);
|
||||
for (i = 1; i < subitemsCount; i++) {
|
||||
incHex(char, ucs2DataSize);
|
||||
if (!sequence) {
|
||||
@ -640,8 +665,10 @@ var BinaryCMapReader = (function BinaryCMapReaderClosure() {
|
||||
incHex(charCode, dataSize);
|
||||
stream.readHexSigned(tmp, dataSize);
|
||||
addHex(charCode, tmp, dataSize);
|
||||
cMap.mapOne(hexToInt(char, ucs2DataSize),
|
||||
hexToStr(charCode, dataSize));
|
||||
cMap.mapOne(
|
||||
hexToInt(char, ucs2DataSize),
|
||||
hexToStr(charCode, dataSize)
|
||||
);
|
||||
}
|
||||
break;
|
||||
case 5: // bfrange
|
||||
@ -649,9 +676,11 @@ var BinaryCMapReader = (function BinaryCMapReaderClosure() {
|
||||
stream.readHexNumber(end, ucs2DataSize);
|
||||
addHex(end, start, ucs2DataSize);
|
||||
stream.readHex(charCode, dataSize);
|
||||
cMap.mapBfRange(hexToInt(start, ucs2DataSize),
|
||||
hexToInt(end, ucs2DataSize),
|
||||
hexToStr(charCode, dataSize));
|
||||
cMap.mapBfRange(
|
||||
hexToInt(start, ucs2DataSize),
|
||||
hexToInt(end, ucs2DataSize),
|
||||
hexToStr(charCode, dataSize)
|
||||
);
|
||||
for (i = 1; i < subitemsCount; i++) {
|
||||
incHex(end, ucs2DataSize);
|
||||
if (!sequence) {
|
||||
@ -663,13 +692,15 @@ var BinaryCMapReader = (function BinaryCMapReaderClosure() {
|
||||
stream.readHexNumber(end, ucs2DataSize);
|
||||
addHex(end, start, ucs2DataSize);
|
||||
stream.readHex(charCode, dataSize);
|
||||
cMap.mapBfRange(hexToInt(start, ucs2DataSize),
|
||||
hexToInt(end, ucs2DataSize),
|
||||
hexToStr(charCode, dataSize));
|
||||
cMap.mapBfRange(
|
||||
hexToInt(start, ucs2DataSize),
|
||||
hexToInt(end, ucs2DataSize),
|
||||
hexToStr(charCode, dataSize)
|
||||
);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
reject(new Error('processBinaryCMap: Unknown type: ' + type));
|
||||
reject(new Error("processBinaryCMap: Unknown type: " + type));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -702,13 +733,13 @@ var CMapFactory = (function CMapFactoryClosure() {
|
||||
|
||||
function expectString(obj) {
|
||||
if (!isString(obj)) {
|
||||
throw new FormatError('Malformed CMap: expected string.');
|
||||
throw new FormatError("Malformed CMap: expected string.");
|
||||
}
|
||||
}
|
||||
|
||||
function expectInt(obj) {
|
||||
if (!Number.isInteger(obj)) {
|
||||
throw new FormatError('Malformed CMap: expected int.');
|
||||
throw new FormatError("Malformed CMap: expected int.");
|
||||
}
|
||||
}
|
||||
|
||||
@ -718,7 +749,7 @@ var CMapFactory = (function CMapFactoryClosure() {
|
||||
if (isEOF(obj)) {
|
||||
break;
|
||||
}
|
||||
if (isCmd(obj, 'endbfchar')) {
|
||||
if (isCmd(obj, "endbfchar")) {
|
||||
return;
|
||||
}
|
||||
expectString(obj);
|
||||
@ -737,7 +768,7 @@ var CMapFactory = (function CMapFactoryClosure() {
|
||||
if (isEOF(obj)) {
|
||||
break;
|
||||
}
|
||||
if (isCmd(obj, 'endbfrange')) {
|
||||
if (isCmd(obj, "endbfrange")) {
|
||||
return;
|
||||
}
|
||||
expectString(obj);
|
||||
@ -749,10 +780,10 @@ var CMapFactory = (function CMapFactoryClosure() {
|
||||
if (Number.isInteger(obj) || isString(obj)) {
|
||||
var dstLow = Number.isInteger(obj) ? String.fromCharCode(obj) : obj;
|
||||
cMap.mapBfRange(low, high, dstLow);
|
||||
} else if (isCmd(obj, '[')) {
|
||||
} else if (isCmd(obj, "[")) {
|
||||
obj = lexer.getObj();
|
||||
var array = [];
|
||||
while (!isCmd(obj, ']') && !isEOF(obj)) {
|
||||
while (!isCmd(obj, "]") && !isEOF(obj)) {
|
||||
array.push(obj);
|
||||
obj = lexer.getObj();
|
||||
}
|
||||
@ -761,7 +792,7 @@ var CMapFactory = (function CMapFactoryClosure() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
throw new FormatError('Invalid bf range.');
|
||||
throw new FormatError("Invalid bf range.");
|
||||
}
|
||||
|
||||
function parseCidChar(cMap, lexer) {
|
||||
@ -770,7 +801,7 @@ var CMapFactory = (function CMapFactoryClosure() {
|
||||
if (isEOF(obj)) {
|
||||
break;
|
||||
}
|
||||
if (isCmd(obj, 'endcidchar')) {
|
||||
if (isCmd(obj, "endcidchar")) {
|
||||
return;
|
||||
}
|
||||
expectString(obj);
|
||||
@ -788,7 +819,7 @@ var CMapFactory = (function CMapFactoryClosure() {
|
||||
if (isEOF(obj)) {
|
||||
break;
|
||||
}
|
||||
if (isCmd(obj, 'endcidrange')) {
|
||||
if (isCmd(obj, "endcidrange")) {
|
||||
return;
|
||||
}
|
||||
expectString(obj);
|
||||
@ -809,7 +840,7 @@ var CMapFactory = (function CMapFactoryClosure() {
|
||||
if (isEOF(obj)) {
|
||||
break;
|
||||
}
|
||||
if (isCmd(obj, 'endcodespacerange')) {
|
||||
if (isCmd(obj, "endcodespacerange")) {
|
||||
return;
|
||||
}
|
||||
if (!isString(obj)) {
|
||||
@ -823,7 +854,7 @@ var CMapFactory = (function CMapFactoryClosure() {
|
||||
var high = strToInt(obj);
|
||||
cMap.addCodespaceRange(obj.length, low, high);
|
||||
}
|
||||
throw new FormatError('Invalid codespace range.');
|
||||
throw new FormatError("Invalid codespace range.");
|
||||
}
|
||||
|
||||
function parseWMode(cMap, lexer) {
|
||||
@ -849,34 +880,34 @@ var CMapFactory = (function CMapFactoryClosure() {
|
||||
if (isEOF(obj)) {
|
||||
break;
|
||||
} else if (isName(obj)) {
|
||||
if (obj.name === 'WMode') {
|
||||
if (obj.name === "WMode") {
|
||||
parseWMode(cMap, lexer);
|
||||
} else if (obj.name === 'CMapName') {
|
||||
} else if (obj.name === "CMapName") {
|
||||
parseCMapName(cMap, lexer);
|
||||
}
|
||||
previous = obj;
|
||||
} else if (isCmd(obj)) {
|
||||
switch (obj.cmd) {
|
||||
case 'endcmap':
|
||||
case "endcmap":
|
||||
break objLoop;
|
||||
case 'usecmap':
|
||||
case "usecmap":
|
||||
if (isName(previous)) {
|
||||
embeddedUseCMap = previous.name;
|
||||
}
|
||||
break;
|
||||
case 'begincodespacerange':
|
||||
case "begincodespacerange":
|
||||
parseCodespaceRange(cMap, lexer);
|
||||
break;
|
||||
case 'beginbfchar':
|
||||
case "beginbfchar":
|
||||
parseBfChar(cMap, lexer);
|
||||
break;
|
||||
case 'begincidchar':
|
||||
case "begincidchar":
|
||||
parseCidChar(cMap, lexer);
|
||||
break;
|
||||
case 'beginbfrange':
|
||||
case "beginbfrange":
|
||||
parseBfRange(cMap, lexer);
|
||||
break;
|
||||
case 'begincidrange':
|
||||
case "begincidrange":
|
||||
parseCidRange(cMap, lexer);
|
||||
break;
|
||||
}
|
||||
@ -885,7 +916,7 @@ var CMapFactory = (function CMapFactoryClosure() {
|
||||
if (ex instanceof MissingDataException) {
|
||||
throw ex;
|
||||
}
|
||||
warn('Invalid cMap data: ' + ex);
|
||||
warn("Invalid cMap data: " + ex);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -926,26 +957,29 @@ var CMapFactory = (function CMapFactoryClosure() {
|
||||
}
|
||||
|
||||
function createBuiltInCMap(name, fetchBuiltInCMap) {
|
||||
if (name === 'Identity-H') {
|
||||
if (name === "Identity-H") {
|
||||
return Promise.resolve(new IdentityCMap(false, 2));
|
||||
} else if (name === 'Identity-V') {
|
||||
} else if (name === "Identity-V") {
|
||||
return Promise.resolve(new IdentityCMap(true, 2));
|
||||
}
|
||||
if (!BUILT_IN_CMAPS.includes(name)) {
|
||||
return Promise.reject(new Error('Unknown CMap name: ' + name));
|
||||
return Promise.reject(new Error("Unknown CMap name: " + name));
|
||||
}
|
||||
if (!fetchBuiltInCMap) {
|
||||
return Promise.reject(new Error(
|
||||
'Built-in CMap parameters are not provided.'));
|
||||
return Promise.reject(
|
||||
new Error("Built-in CMap parameters are not provided.")
|
||||
);
|
||||
}
|
||||
|
||||
return fetchBuiltInCMap(name).then(function (data) {
|
||||
var cMapData = data.cMapData, compressionType = data.compressionType;
|
||||
return fetchBuiltInCMap(name).then(function(data) {
|
||||
var cMapData = data.cMapData,
|
||||
compressionType = data.compressionType;
|
||||
var cMap = new CMap(true);
|
||||
|
||||
if (compressionType === CMapCompressionType.BINARY) {
|
||||
return new BinaryCMapReader().process(cMapData, cMap,
|
||||
function (useCMap) {
|
||||
return new BinaryCMapReader().process(cMapData, cMap, function(
|
||||
useCMap
|
||||
) {
|
||||
return extendCMap(cMap, fetchBuiltInCMap, useCMap);
|
||||
});
|
||||
}
|
||||
@ -953,8 +987,11 @@ var CMapFactory = (function CMapFactoryClosure() {
|
||||
var lexer = new Lexer(new Stream(cMapData));
|
||||
return parseCMap(cMap, lexer, fetchBuiltInCMap, null);
|
||||
}
|
||||
return Promise.reject(new Error(
|
||||
'TODO: Only BINARY/NONE CMap compression is currently supported.'));
|
||||
return Promise.reject(
|
||||
new Error(
|
||||
"TODO: Only BINARY/NONE CMap compression is currently supported."
|
||||
)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@ -969,21 +1006,18 @@ var CMapFactory = (function CMapFactoryClosure() {
|
||||
} else if (isStream(encoding)) {
|
||||
var cMap = new CMap();
|
||||
var lexer = new Lexer(encoding);
|
||||
return parseCMap(cMap, lexer, fetchBuiltInCMap, useCMap).then(
|
||||
function (parsedCMap) {
|
||||
return parseCMap(cMap, lexer, fetchBuiltInCMap, useCMap).then(function(
|
||||
parsedCMap
|
||||
) {
|
||||
if (parsedCMap.isIdentityCMap) {
|
||||
return createBuiltInCMap(parsedCMap.name, fetchBuiltInCMap);
|
||||
}
|
||||
return parsedCMap;
|
||||
});
|
||||
}
|
||||
return Promise.reject(new Error('Encoding required.'));
|
||||
return Promise.reject(new Error("Encoding required."));
|
||||
},
|
||||
};
|
||||
})();
|
||||
|
||||
export {
|
||||
CMap,
|
||||
IdentityCMap,
|
||||
CMapFactory,
|
||||
};
|
||||
export { CMap, IdentityCMap, CMapFactory };
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -14,7 +14,7 @@
|
||||
*/
|
||||
/* eslint no-var: error */
|
||||
|
||||
import { assert, BaseException, warn } from '../shared/util';
|
||||
import { assert, BaseException, warn } from "../shared/util";
|
||||
|
||||
function getLookupTableFactory(initializer) {
|
||||
let lookup;
|
||||
@ -36,9 +36,9 @@ class MissingDataException extends BaseException {
|
||||
}
|
||||
}
|
||||
|
||||
class XRefEntryException extends BaseException { }
|
||||
class XRefEntryException extends BaseException {}
|
||||
|
||||
class XRefParseException extends BaseException { }
|
||||
class XRefParseException extends BaseException {}
|
||||
|
||||
/**
|
||||
* Get the value of an inheritable property.
|
||||
@ -61,8 +61,12 @@ class XRefParseException extends BaseException { }
|
||||
* chain, for example to be able to find `\Resources` placed on multiple
|
||||
* levels of the tree. The default value is `true`.
|
||||
*/
|
||||
function getInheritableProperty({ dict, key, getArray = false,
|
||||
stopWhenFound = true, }) {
|
||||
function getInheritableProperty({
|
||||
dict,
|
||||
key,
|
||||
getArray = false,
|
||||
stopWhenFound = true,
|
||||
}) {
|
||||
const LOOP_LIMIT = 100;
|
||||
let loopCount = 0;
|
||||
let values;
|
||||
@ -82,15 +86,16 @@ function getInheritableProperty({ dict, key, getArray = false,
|
||||
warn(`getInheritableProperty: maximum loop count exceeded for "${key}"`);
|
||||
break;
|
||||
}
|
||||
dict = dict.get('Parent');
|
||||
dict = dict.get("Parent");
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
// prettier-ignore
|
||||
const ROMAN_NUMBER_MAP = [
|
||||
'', 'C', 'CC', 'CCC', 'CD', 'D', 'DC', 'DCC', 'DCCC', 'CM',
|
||||
'', 'X', 'XX', 'XXX', 'XL', 'L', 'LX', 'LXX', 'LXXX', 'XC',
|
||||
'', 'I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX'
|
||||
"", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM",
|
||||
"", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC",
|
||||
"", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"
|
||||
];
|
||||
|
||||
/**
|
||||
@ -101,13 +106,16 @@ const ROMAN_NUMBER_MAP = [
|
||||
* @returns {string} The resulting Roman number.
|
||||
*/
|
||||
function toRomanNumerals(number, lowerCase = false) {
|
||||
assert(Number.isInteger(number) && number > 0,
|
||||
'The number should be a positive integer.');
|
||||
let pos, romanBuf = [];
|
||||
assert(
|
||||
Number.isInteger(number) && number > 0,
|
||||
"The number should be a positive integer."
|
||||
);
|
||||
let pos,
|
||||
romanBuf = [];
|
||||
// Thousands
|
||||
while (number >= 1000) {
|
||||
number -= 1000;
|
||||
romanBuf.push('M');
|
||||
romanBuf.push("M");
|
||||
}
|
||||
// Hundreds
|
||||
pos = (number / 100) | 0;
|
||||
@ -120,8 +128,8 @@ function toRomanNumerals(number, lowerCase = false) {
|
||||
// Ones
|
||||
romanBuf.push(ROMAN_NUMBER_MAP[20 + number]);
|
||||
|
||||
const romanStr = romanBuf.join('');
|
||||
return (lowerCase ? romanStr.toLowerCase() : romanStr);
|
||||
const romanStr = romanBuf.join("");
|
||||
return lowerCase ? romanStr.toLowerCase() : romanStr;
|
||||
}
|
||||
|
||||
export {
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -15,35 +15,60 @@
|
||||
/* eslint no-var: error */
|
||||
|
||||
import {
|
||||
assert, FormatError, info, InvalidPDFException, isArrayBuffer, isArrayEqual,
|
||||
isBool, isNum, isSpace, isString, OPS, shadow, stringToBytes,
|
||||
stringToPDFString, Util, warn
|
||||
} from '../shared/util';
|
||||
import { Catalog, ObjectLoader, XRef } from './obj';
|
||||
import { Dict, isDict, isName, isStream, Ref } from './primitives';
|
||||
assert,
|
||||
FormatError,
|
||||
info,
|
||||
InvalidPDFException,
|
||||
isArrayBuffer,
|
||||
isArrayEqual,
|
||||
isBool,
|
||||
isNum,
|
||||
isSpace,
|
||||
isString,
|
||||
OPS,
|
||||
shadow,
|
||||
stringToBytes,
|
||||
stringToPDFString,
|
||||
Util,
|
||||
warn,
|
||||
} from "../shared/util";
|
||||
import { Catalog, ObjectLoader, XRef } from "./obj";
|
||||
import { Dict, isDict, isName, isStream, Ref } from "./primitives";
|
||||
import {
|
||||
getInheritableProperty, MissingDataException, XRefEntryException,
|
||||
XRefParseException
|
||||
} from './core_utils';
|
||||
import { NullStream, Stream, StreamsSequenceStream } from './stream';
|
||||
import { AnnotationFactory } from './annotation';
|
||||
import { calculateMD5 } from './crypto';
|
||||
import { Linearization } from './parser';
|
||||
import { OperatorList } from './operator_list';
|
||||
import { PartialEvaluator } from './evaluator';
|
||||
import { PDFFunctionFactory } from './function';
|
||||
getInheritableProperty,
|
||||
MissingDataException,
|
||||
XRefEntryException,
|
||||
XRefParseException,
|
||||
} from "./core_utils";
|
||||
import { NullStream, Stream, StreamsSequenceStream } from "./stream";
|
||||
import { AnnotationFactory } from "./annotation";
|
||||
import { calculateMD5 } from "./crypto";
|
||||
import { Linearization } from "./parser";
|
||||
import { OperatorList } from "./operator_list";
|
||||
import { PartialEvaluator } from "./evaluator";
|
||||
import { PDFFunctionFactory } from "./function";
|
||||
|
||||
const DEFAULT_USER_UNIT = 1.0;
|
||||
const LETTER_SIZE_MEDIABOX = [0, 0, 612, 792];
|
||||
|
||||
function isAnnotationRenderable(annotation, intent) {
|
||||
return (intent === 'display' && annotation.viewable) ||
|
||||
(intent === 'print' && annotation.printable);
|
||||
return (
|
||||
(intent === "display" && annotation.viewable) ||
|
||||
(intent === "print" && annotation.printable)
|
||||
);
|
||||
}
|
||||
|
||||
class Page {
|
||||
constructor({ pdfManager, xref, pageIndex, pageDict, ref, fontCache,
|
||||
builtInCMapCache, pdfFunctionFactory, }) {
|
||||
constructor({
|
||||
pdfManager,
|
||||
xref,
|
||||
pageIndex,
|
||||
pageDict,
|
||||
ref,
|
||||
fontCache,
|
||||
builtInCMapCache,
|
||||
pdfFunctionFactory,
|
||||
}) {
|
||||
this.pdfManager = pdfManager;
|
||||
this.pageIndex = pageIndex;
|
||||
this.pageDict = pageDict;
|
||||
@ -72,8 +97,12 @@ class Page {
|
||||
* @private
|
||||
*/
|
||||
_getInheritableProperty(key, getArray = false) {
|
||||
const value = getInheritableProperty({ dict: this.pageDict, key, getArray,
|
||||
stopWhenFound: false, });
|
||||
const value = getInheritableProperty({
|
||||
dict: this.pageDict,
|
||||
key,
|
||||
getArray,
|
||||
stopWhenFound: false,
|
||||
});
|
||||
if (!Array.isArray(value)) {
|
||||
return value;
|
||||
}
|
||||
@ -84,22 +113,25 @@ class Page {
|
||||
}
|
||||
|
||||
get content() {
|
||||
return this.pageDict.get('Contents');
|
||||
return this.pageDict.get("Contents");
|
||||
}
|
||||
|
||||
get resources() {
|
||||
// For robustness: The spec states that a \Resources entry has to be
|
||||
// present, but can be empty. Some documents still omit it; in this case
|
||||
// we return an empty dictionary.
|
||||
return shadow(this, 'resources',
|
||||
this._getInheritableProperty('Resources') || Dict.empty);
|
||||
return shadow(
|
||||
this,
|
||||
"resources",
|
||||
this._getInheritableProperty("Resources") || Dict.empty
|
||||
);
|
||||
}
|
||||
|
||||
_getBoundingBox(name) {
|
||||
const box = this._getInheritableProperty(name, /* getArray = */ true);
|
||||
|
||||
if (Array.isArray(box) && box.length === 4) {
|
||||
if ((box[2] - box[0]) !== 0 && (box[3] - box[1]) !== 0) {
|
||||
if (box[2] - box[0] !== 0 && box[3] - box[1] !== 0) {
|
||||
return box;
|
||||
}
|
||||
warn(`Empty /${name} entry.`);
|
||||
@ -109,22 +141,28 @@ class Page {
|
||||
|
||||
get mediaBox() {
|
||||
// Reset invalid media box to letter size.
|
||||
return shadow(this, 'mediaBox',
|
||||
this._getBoundingBox('MediaBox') || LETTER_SIZE_MEDIABOX);
|
||||
return shadow(
|
||||
this,
|
||||
"mediaBox",
|
||||
this._getBoundingBox("MediaBox") || LETTER_SIZE_MEDIABOX
|
||||
);
|
||||
}
|
||||
|
||||
get cropBox() {
|
||||
// Reset invalid crop box to media box.
|
||||
return shadow(this, 'cropBox',
|
||||
this._getBoundingBox('CropBox') || this.mediaBox);
|
||||
return shadow(
|
||||
this,
|
||||
"cropBox",
|
||||
this._getBoundingBox("CropBox") || this.mediaBox
|
||||
);
|
||||
}
|
||||
|
||||
get userUnit() {
|
||||
let obj = this.pageDict.get('UserUnit');
|
||||
let obj = this.pageDict.get("UserUnit");
|
||||
if (!isNum(obj) || obj <= 0) {
|
||||
obj = DEFAULT_USER_UNIT;
|
||||
}
|
||||
return shadow(this, 'userUnit', obj);
|
||||
return shadow(this, "userUnit", obj);
|
||||
}
|
||||
|
||||
get view() {
|
||||
@ -132,23 +170,23 @@ class Page {
|
||||
// "The crop, bleed, trim, and art boxes should not ordinarily
|
||||
// extend beyond the boundaries of the media box. If they do, they are
|
||||
// effectively reduced to their intersection with the media box."
|
||||
const { cropBox, mediaBox, } = this;
|
||||
const { cropBox, mediaBox } = this;
|
||||
let view;
|
||||
if (cropBox === mediaBox || isArrayEqual(cropBox, mediaBox)) {
|
||||
view = mediaBox;
|
||||
} else {
|
||||
const box = Util.intersect(cropBox, mediaBox);
|
||||
if (box && ((box[2] - box[0]) !== 0 && (box[3] - box[1]) !== 0)) {
|
||||
if (box && box[2] - box[0] !== 0 && box[3] - box[1] !== 0) {
|
||||
view = box;
|
||||
} else {
|
||||
warn('Empty /CropBox and /MediaBox intersection.');
|
||||
warn("Empty /CropBox and /MediaBox intersection.");
|
||||
}
|
||||
}
|
||||
return shadow(this, 'view', view || mediaBox);
|
||||
return shadow(this, "view", view || mediaBox);
|
||||
}
|
||||
|
||||
get rotate() {
|
||||
let rotate = this._getInheritableProperty('Rotate') || 0;
|
||||
let rotate = this._getInheritableProperty("Rotate") || 0;
|
||||
|
||||
// Normalize rotation so it's a multiple of 90 and between 0 and 270.
|
||||
if (rotate % 90 !== 0) {
|
||||
@ -160,7 +198,7 @@ class Page {
|
||||
// rotation. The following is the other implementation of modulo.
|
||||
rotate = ((rotate % 360) + 360) % 360;
|
||||
}
|
||||
return shadow(this, 'rotate', rotate);
|
||||
return shadow(this, "rotate", rotate);
|
||||
}
|
||||
|
||||
getContentStream() {
|
||||
@ -187,7 +225,7 @@ class Page {
|
||||
loadResources(keys) {
|
||||
if (!this.resourcesPromise) {
|
||||
// TODO: add async `_getInheritableProperty` and remove this.
|
||||
this.resourcesPromise = this.pdfManager.ensure(this, 'resources');
|
||||
this.resourcesPromise = this.pdfManager.ensure(this, "resources");
|
||||
}
|
||||
return this.resourcesPromise.then(() => {
|
||||
const objectLoader = new ObjectLoader(this.resources, keys, this.xref);
|
||||
@ -195,16 +233,18 @@ class Page {
|
||||
});
|
||||
}
|
||||
|
||||
getOperatorList({ handler, sink, task, intent, renderInteractiveForms, }) {
|
||||
const contentStreamPromise = this.pdfManager.ensure(this,
|
||||
'getContentStream');
|
||||
getOperatorList({ handler, sink, task, intent, renderInteractiveForms }) {
|
||||
const contentStreamPromise = this.pdfManager.ensure(
|
||||
this,
|
||||
"getContentStream"
|
||||
);
|
||||
const resourcesPromise = this.loadResources([
|
||||
'ExtGState',
|
||||
'ColorSpace',
|
||||
'Pattern',
|
||||
'Shading',
|
||||
'XObject',
|
||||
'Font',
|
||||
"ExtGState",
|
||||
"ColorSpace",
|
||||
"Pattern",
|
||||
"Shading",
|
||||
"XObject",
|
||||
"Font",
|
||||
]);
|
||||
|
||||
const partialEvaluator = new PartialEvaluator({
|
||||
@ -222,61 +262,76 @@ class Page {
|
||||
const pageListPromise = dataPromises.then(([contentStream]) => {
|
||||
const opList = new OperatorList(intent, sink, this.pageIndex);
|
||||
|
||||
handler.send('StartRenderPage', {
|
||||
handler.send("StartRenderPage", {
|
||||
transparency: partialEvaluator.hasBlendModes(this.resources),
|
||||
pageIndex: this.pageIndex,
|
||||
intent,
|
||||
});
|
||||
|
||||
return partialEvaluator.getOperatorList({
|
||||
stream: contentStream,
|
||||
task,
|
||||
resources: this.resources,
|
||||
operatorList: opList,
|
||||
}).then(function() {
|
||||
return opList;
|
||||
});
|
||||
return partialEvaluator
|
||||
.getOperatorList({
|
||||
stream: contentStream,
|
||||
task,
|
||||
resources: this.resources,
|
||||
operatorList: opList,
|
||||
})
|
||||
.then(function() {
|
||||
return opList;
|
||||
});
|
||||
});
|
||||
|
||||
// Fetch the page's annotations and add their operator lists to the
|
||||
// page's operator list to render them.
|
||||
return Promise.all([pageListPromise, this._parsedAnnotations]).then(
|
||||
function([pageOpList, annotations]) {
|
||||
if (annotations.length === 0) {
|
||||
pageOpList.flush(true);
|
||||
return { length: pageOpList.totalLength, };
|
||||
}
|
||||
|
||||
// Collect the operator list promises for the annotations. Each promise
|
||||
// is resolved with the complete operator list for a single annotation.
|
||||
const opListPromises = [];
|
||||
for (const annotation of annotations) {
|
||||
if (isAnnotationRenderable(annotation, intent)) {
|
||||
opListPromises.push(annotation.getOperatorList(
|
||||
partialEvaluator, task, renderInteractiveForms));
|
||||
function([pageOpList, annotations]) {
|
||||
if (annotations.length === 0) {
|
||||
pageOpList.flush(true);
|
||||
return { length: pageOpList.totalLength };
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.all(opListPromises).then(function(opLists) {
|
||||
pageOpList.addOp(OPS.beginAnnotations, []);
|
||||
for (const opList of opLists) {
|
||||
pageOpList.addOpList(opList);
|
||||
// Collect the operator list promises for the annotations. Each promise
|
||||
// is resolved with the complete operator list for a single annotation.
|
||||
const opListPromises = [];
|
||||
for (const annotation of annotations) {
|
||||
if (isAnnotationRenderable(annotation, intent)) {
|
||||
opListPromises.push(
|
||||
annotation.getOperatorList(
|
||||
partialEvaluator,
|
||||
task,
|
||||
renderInteractiveForms
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
pageOpList.addOp(OPS.endAnnotations, []);
|
||||
pageOpList.flush(true);
|
||||
return { length: pageOpList.totalLength, };
|
||||
});
|
||||
});
|
||||
|
||||
return Promise.all(opListPromises).then(function(opLists) {
|
||||
pageOpList.addOp(OPS.beginAnnotations, []);
|
||||
for (const opList of opLists) {
|
||||
pageOpList.addOpList(opList);
|
||||
}
|
||||
pageOpList.addOp(OPS.endAnnotations, []);
|
||||
pageOpList.flush(true);
|
||||
return { length: pageOpList.totalLength };
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
extractTextContent({ handler, task, normalizeWhitespace, sink,
|
||||
combineTextItems, }) {
|
||||
const contentStreamPromise = this.pdfManager.ensure(this,
|
||||
'getContentStream');
|
||||
extractTextContent({
|
||||
handler,
|
||||
task,
|
||||
normalizeWhitespace,
|
||||
sink,
|
||||
combineTextItems,
|
||||
}) {
|
||||
const contentStreamPromise = this.pdfManager.ensure(
|
||||
this,
|
||||
"getContentStream"
|
||||
);
|
||||
const resourcesPromise = this.loadResources([
|
||||
'ExtGState',
|
||||
'XObject',
|
||||
'Font',
|
||||
"ExtGState",
|
||||
"XObject",
|
||||
"Font",
|
||||
]);
|
||||
|
||||
const dataPromises = Promise.all([contentStreamPromise, resourcesPromise]);
|
||||
@ -316,46 +371,62 @@ class Page {
|
||||
}
|
||||
|
||||
get annotations() {
|
||||
return shadow(this, 'annotations',
|
||||
this._getInheritableProperty('Annots') || []);
|
||||
return shadow(
|
||||
this,
|
||||
"annotations",
|
||||
this._getInheritableProperty("Annots") || []
|
||||
);
|
||||
}
|
||||
|
||||
get _parsedAnnotations() {
|
||||
const parsedAnnotations =
|
||||
this.pdfManager.ensure(this, 'annotations').then(() => {
|
||||
const parsedAnnotations = this.pdfManager
|
||||
.ensure(this, "annotations")
|
||||
.then(() => {
|
||||
const annotationRefs = this.annotations;
|
||||
const annotationPromises = [];
|
||||
for (let i = 0, ii = annotationRefs.length; i < ii; i++) {
|
||||
annotationPromises.push(AnnotationFactory.create(
|
||||
this.xref, annotationRefs[i], this.pdfManager, this.idFactory));
|
||||
annotationPromises.push(
|
||||
AnnotationFactory.create(
|
||||
this.xref,
|
||||
annotationRefs[i],
|
||||
this.pdfManager,
|
||||
this.idFactory
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return Promise.all(annotationPromises).then(function(annotations) {
|
||||
return annotations.filter(function isDefined(annotation) {
|
||||
return !!annotation;
|
||||
});
|
||||
}, function(reason) {
|
||||
warn(`_parsedAnnotations: "${reason}".`);
|
||||
return [];
|
||||
});
|
||||
return Promise.all(annotationPromises).then(
|
||||
function(annotations) {
|
||||
return annotations.filter(function isDefined(annotation) {
|
||||
return !!annotation;
|
||||
});
|
||||
},
|
||||
function(reason) {
|
||||
warn(`_parsedAnnotations: "${reason}".`);
|
||||
return [];
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
return shadow(this, '_parsedAnnotations', parsedAnnotations);
|
||||
return shadow(this, "_parsedAnnotations", parsedAnnotations);
|
||||
}
|
||||
}
|
||||
|
||||
const PDF_HEADER_SIGNATURE = new Uint8Array([0x25, 0x50, 0x44, 0x46, 0x2D]);
|
||||
const PDF_HEADER_SIGNATURE = new Uint8Array([0x25, 0x50, 0x44, 0x46, 0x2d]);
|
||||
// prettier-ignore
|
||||
const STARTXREF_SIGNATURE = new Uint8Array([
|
||||
0x73, 0x74, 0x61, 0x72, 0x74, 0x78, 0x72, 0x65, 0x66]);
|
||||
const ENDOBJ_SIGNATURE = new Uint8Array([0x65, 0x6E, 0x64, 0x6F, 0x62, 0x6A]);
|
||||
const ENDOBJ_SIGNATURE = new Uint8Array([0x65, 0x6e, 0x64, 0x6f, 0x62, 0x6a]);
|
||||
|
||||
const FINGERPRINT_FIRST_BYTES = 1024;
|
||||
const EMPTY_FINGERPRINT =
|
||||
'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00';
|
||||
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
|
||||
|
||||
function find(stream, signature, limit = 1024, backwards = false) {
|
||||
if (typeof PDFJSDev === 'undefined' ||
|
||||
PDFJSDev.test('!PRODUCTION || TESTING')) {
|
||||
if (
|
||||
typeof PDFJSDev === "undefined" ||
|
||||
PDFJSDev.test("!PRODUCTION || TESTING")
|
||||
) {
|
||||
assert(limit > 0, 'The "limit" must be a positive integer.');
|
||||
}
|
||||
const signatureLength = signature.length;
|
||||
@ -372,24 +443,29 @@ function find(stream, signature, limit = 1024, backwards = false) {
|
||||
let pos = scanBytes.length - 1;
|
||||
while (pos >= signatureEnd) {
|
||||
let j = 0;
|
||||
while (j < signatureLength &&
|
||||
scanBytes[pos - j] === signature[signatureEnd - j]) {
|
||||
while (
|
||||
j < signatureLength &&
|
||||
scanBytes[pos - j] === signature[signatureEnd - j]
|
||||
) {
|
||||
j++;
|
||||
}
|
||||
if (j >= signatureLength) { // `signature` found.
|
||||
stream.pos += (pos - signatureEnd);
|
||||
if (j >= signatureLength) {
|
||||
// `signature` found.
|
||||
stream.pos += pos - signatureEnd;
|
||||
return true;
|
||||
}
|
||||
pos--;
|
||||
}
|
||||
} else { // forwards
|
||||
} else {
|
||||
// forwards
|
||||
let pos = 0;
|
||||
while (pos <= scanLength) {
|
||||
let j = 0;
|
||||
while (j < signatureLength && scanBytes[pos + j] === signature[j]) {
|
||||
j++;
|
||||
}
|
||||
if (j >= signatureLength) { // `signature` found.
|
||||
if (j >= signatureLength) {
|
||||
// `signature` found.
|
||||
stream.pos += pos;
|
||||
return true;
|
||||
}
|
||||
@ -410,11 +486,12 @@ class PDFDocument {
|
||||
} else if (isArrayBuffer(arg)) {
|
||||
stream = new Stream(arg);
|
||||
} else {
|
||||
throw new Error('PDFDocument: Unknown argument type');
|
||||
throw new Error("PDFDocument: Unknown argument type");
|
||||
}
|
||||
if (stream.length <= 0) {
|
||||
throw new InvalidPDFException(
|
||||
'The PDF file is empty, i.e. its size is zero bytes.');
|
||||
"The PDF file is empty, i.e. its size is zero bytes."
|
||||
);
|
||||
}
|
||||
|
||||
this.pdfManager = pdfManager;
|
||||
@ -431,17 +508,17 @@ class PDFDocument {
|
||||
parse(recoveryMode) {
|
||||
this.setup(recoveryMode);
|
||||
|
||||
const version = this.catalog.catDict.get('Version');
|
||||
const version = this.catalog.catDict.get("Version");
|
||||
if (isName(version)) {
|
||||
this.pdfFormatVersion = version.name;
|
||||
}
|
||||
|
||||
// Check if AcroForms are present in the document.
|
||||
try {
|
||||
this.acroForm = this.catalog.catDict.get('AcroForm');
|
||||
this.acroForm = this.catalog.catDict.get("AcroForm");
|
||||
if (this.acroForm) {
|
||||
this.xfa = this.acroForm.get('XFA');
|
||||
const fields = this.acroForm.get('Fields');
|
||||
this.xfa = this.acroForm.get("XFA");
|
||||
const fields = this.acroForm.get("Fields");
|
||||
if ((!Array.isArray(fields) || fields.length === 0) && !this.xfa) {
|
||||
this.acroForm = null; // No fields and no XFA, so it's not a form.
|
||||
}
|
||||
@ -450,13 +527,13 @@ class PDFDocument {
|
||||
if (ex instanceof MissingDataException) {
|
||||
throw ex;
|
||||
}
|
||||
info('Cannot fetch AcroForm entry; assuming no AcroForms are present');
|
||||
info("Cannot fetch AcroForm entry; assuming no AcroForms are present");
|
||||
this.acroForm = null;
|
||||
}
|
||||
|
||||
// Check if a Collection dictionary is present in the document.
|
||||
try {
|
||||
const collection = this.catalog.catDict.get('Collection');
|
||||
const collection = this.catalog.catDict.get("Collection");
|
||||
if (isDict(collection) && collection.getKeys().length > 0) {
|
||||
this.collection = collection;
|
||||
}
|
||||
@ -464,7 +541,7 @@ class PDFDocument {
|
||||
if (ex instanceof MissingDataException) {
|
||||
throw ex;
|
||||
}
|
||||
info('Cannot fetch Collection dictionary.');
|
||||
info("Cannot fetch Collection dictionary.");
|
||||
}
|
||||
}
|
||||
|
||||
@ -478,7 +555,7 @@ class PDFDocument {
|
||||
}
|
||||
info(err);
|
||||
}
|
||||
return shadow(this, 'linearization', linearization);
|
||||
return shadow(this, "linearization", linearization);
|
||||
}
|
||||
|
||||
get startXRef() {
|
||||
@ -489,13 +566,14 @@ class PDFDocument {
|
||||
// Find the end of the first object.
|
||||
stream.reset();
|
||||
if (find(stream, ENDOBJ_SIGNATURE)) {
|
||||
startXRef = (stream.pos + 6) - stream.start;
|
||||
startXRef = stream.pos + 6 - stream.start;
|
||||
}
|
||||
} else {
|
||||
// Find `startxref` by checking backwards from the end of the file.
|
||||
const step = 1024;
|
||||
const startXRefLength = STARTXREF_SIGNATURE.length;
|
||||
let found = false, pos = stream.end;
|
||||
let found = false,
|
||||
pos = stream.end;
|
||||
|
||||
while (!found && pos > 0) {
|
||||
pos -= step - startXRefLength;
|
||||
@ -512,8 +590,8 @@ class PDFDocument {
|
||||
do {
|
||||
ch = stream.getByte();
|
||||
} while (isSpace(ch));
|
||||
let str = '';
|
||||
while (ch >= 0x20 && ch <= 0x39) { // < '9'
|
||||
let str = "";
|
||||
while (ch >= /* Space = */ 0x20 && ch <= /* '9' = */ 0x39) {
|
||||
str += String.fromCharCode(ch);
|
||||
ch = stream.getByte();
|
||||
}
|
||||
@ -523,7 +601,7 @@ class PDFDocument {
|
||||
}
|
||||
}
|
||||
}
|
||||
return shadow(this, 'startXRef', startXRef);
|
||||
return shadow(this, "startXRef", startXRef);
|
||||
}
|
||||
|
||||
// Find the header, get the PDF format version and setup the
|
||||
@ -541,8 +619,9 @@ class PDFDocument {
|
||||
|
||||
// Read the PDF format version.
|
||||
const MAX_PDF_VERSION_LENGTH = 12;
|
||||
let version = '', ch;
|
||||
while ((ch = stream.getByte()) > 0x20) { // Space
|
||||
let version = "",
|
||||
ch;
|
||||
while ((ch = stream.getByte()) > /* Space = */ 0x20) {
|
||||
if (version.length >= MAX_PDF_VERSION_LENGTH) {
|
||||
break;
|
||||
}
|
||||
@ -566,7 +645,7 @@ class PDFDocument {
|
||||
get numPages() {
|
||||
const linearization = this.linearization;
|
||||
const num = linearization ? linearization.numPages : this.catalog.numPages;
|
||||
return shadow(this, 'numPages', num);
|
||||
return shadow(this, "numPages", num);
|
||||
}
|
||||
|
||||
get documentInfo() {
|
||||
@ -592,12 +671,12 @@ class PDFDocument {
|
||||
|
||||
let infoDict;
|
||||
try {
|
||||
infoDict = this.xref.trailer.get('Info');
|
||||
infoDict = this.xref.trailer.get("Info");
|
||||
} catch (err) {
|
||||
if (err instanceof MissingDataException) {
|
||||
throw err;
|
||||
}
|
||||
info('The document information dictionary is invalid.');
|
||||
info("The document information dictionary is invalid.");
|
||||
}
|
||||
|
||||
if (isDict(infoDict)) {
|
||||
@ -609,12 +688,12 @@ class PDFDocument {
|
||||
if (DocumentInfoValidators[key]) {
|
||||
// Make sure the (standard) value conforms to the specification.
|
||||
if (DocumentInfoValidators[key](value)) {
|
||||
docInfo[key] = (typeof value !== 'string' ?
|
||||
value : stringToPDFString(value));
|
||||
docInfo[key] =
|
||||
typeof value !== "string" ? value : stringToPDFString(value);
|
||||
} else {
|
||||
info(`Bad value in document info for "${key}".`);
|
||||
}
|
||||
} else if (typeof key === 'string') {
|
||||
} else if (typeof key === "string") {
|
||||
// For custom values, only accept white-listed types to prevent
|
||||
// errors that would occur when trying to send non-serializable
|
||||
// objects to the main-thread (for example `Dict` or `Stream`).
|
||||
@ -628,67 +707,83 @@ class PDFDocument {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!docInfo['Custom']) {
|
||||
docInfo['Custom'] = Object.create(null);
|
||||
if (!docInfo["Custom"]) {
|
||||
docInfo["Custom"] = Object.create(null);
|
||||
}
|
||||
docInfo['Custom'][key] = customValue;
|
||||
docInfo["Custom"][key] = customValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
return shadow(this, 'documentInfo', docInfo);
|
||||
return shadow(this, "documentInfo", docInfo);
|
||||
}
|
||||
|
||||
get fingerprint() {
|
||||
let hash;
|
||||
const idArray = this.xref.trailer.get('ID');
|
||||
if (Array.isArray(idArray) && idArray[0] && isString(idArray[0]) &&
|
||||
idArray[0] !== EMPTY_FINGERPRINT) {
|
||||
const idArray = this.xref.trailer.get("ID");
|
||||
if (
|
||||
Array.isArray(idArray) &&
|
||||
idArray[0] &&
|
||||
isString(idArray[0]) &&
|
||||
idArray[0] !== EMPTY_FINGERPRINT
|
||||
) {
|
||||
hash = stringToBytes(idArray[0]);
|
||||
} else {
|
||||
hash = calculateMD5(this.stream.getByteRange(0, FINGERPRINT_FIRST_BYTES),
|
||||
0, FINGERPRINT_FIRST_BYTES);
|
||||
hash = calculateMD5(
|
||||
this.stream.getByteRange(0, FINGERPRINT_FIRST_BYTES),
|
||||
0,
|
||||
FINGERPRINT_FIRST_BYTES
|
||||
);
|
||||
}
|
||||
|
||||
const fingerprintBuf = [];
|
||||
for (let i = 0, ii = hash.length; i < ii; i++) {
|
||||
const hex = hash[i].toString(16);
|
||||
fingerprintBuf.push(hex.padStart(2, '0'));
|
||||
fingerprintBuf.push(hex.padStart(2, "0"));
|
||||
}
|
||||
return shadow(this, 'fingerprint', fingerprintBuf.join(''));
|
||||
return shadow(this, "fingerprint", fingerprintBuf.join(""));
|
||||
}
|
||||
|
||||
_getLinearizationPage(pageIndex) {
|
||||
const { catalog, linearization, } = this;
|
||||
const { catalog, linearization } = this;
|
||||
assert(linearization && linearization.pageFirst === pageIndex);
|
||||
|
||||
const ref = Ref.get(linearization.objectNumberFirst, 0);
|
||||
return this.xref.fetchAsync(ref).then((obj) => {
|
||||
// Ensure that the object that was found is actually a Page dictionary.
|
||||
if (isDict(obj, 'Page') ||
|
||||
(isDict(obj) && !obj.has('Type') && obj.has('Contents'))) {
|
||||
if (ref && !catalog.pageKidsCountCache.has(ref)) {
|
||||
catalog.pageKidsCountCache.put(ref, 1); // Cache the Page reference.
|
||||
return this.xref
|
||||
.fetchAsync(ref)
|
||||
.then(obj => {
|
||||
// Ensure that the object that was found is actually a Page dictionary.
|
||||
if (
|
||||
isDict(obj, "Page") ||
|
||||
(isDict(obj) && !obj.has("Type") && obj.has("Contents"))
|
||||
) {
|
||||
if (ref && !catalog.pageKidsCountCache.has(ref)) {
|
||||
catalog.pageKidsCountCache.put(ref, 1); // Cache the Page reference.
|
||||
}
|
||||
return [obj, ref];
|
||||
}
|
||||
return [obj, ref];
|
||||
}
|
||||
throw new FormatError('The Linearization dictionary doesn\'t point ' +
|
||||
'to a valid Page dictionary.');
|
||||
}).catch((reason) => {
|
||||
info(reason);
|
||||
return catalog.getPageDict(pageIndex);
|
||||
});
|
||||
throw new FormatError(
|
||||
"The Linearization dictionary doesn't point " +
|
||||
"to a valid Page dictionary."
|
||||
);
|
||||
})
|
||||
.catch(reason => {
|
||||
info(reason);
|
||||
return catalog.getPageDict(pageIndex);
|
||||
});
|
||||
}
|
||||
|
||||
getPage(pageIndex) {
|
||||
if (this._pagePromises[pageIndex] !== undefined) {
|
||||
return this._pagePromises[pageIndex];
|
||||
}
|
||||
const { catalog, linearization, } = this;
|
||||
const { catalog, linearization } = this;
|
||||
|
||||
const promise = (linearization && linearization.pageFirst === pageIndex) ?
|
||||
this._getLinearizationPage(pageIndex) : catalog.getPageDict(pageIndex);
|
||||
const promise =
|
||||
linearization && linearization.pageFirst === pageIndex
|
||||
? this._getLinearizationPage(pageIndex)
|
||||
: catalog.getPageDict(pageIndex);
|
||||
|
||||
return this._pagePromises[pageIndex] = promise.then(([pageDict, ref]) => {
|
||||
return (this._pagePromises[pageIndex] = promise.then(([pageDict, ref]) => {
|
||||
return new Page({
|
||||
pdfManager: this.pdfManager,
|
||||
xref: this.xref,
|
||||
@ -699,11 +794,11 @@ class PDFDocument {
|
||||
builtInCMapCache: catalog.builtInCMapCache,
|
||||
pdfFunctionFactory: this.pdfFunctionFactory,
|
||||
});
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
checkFirstPage() {
|
||||
return this.getPage(0).catch(async (reason) => {
|
||||
return this.getPage(0).catch(async reason => {
|
||||
if (reason instanceof XRefEntryException) {
|
||||
// Clear out the various caches to ensure that we haven't stored any
|
||||
// inconsistent and/or incorrect state, since that could easily break
|
||||
@ -725,7 +820,4 @@ class PDFDocument {
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
Page,
|
||||
PDFDocument,
|
||||
};
|
||||
export { Page, PDFDocument };
|
||||
|
@ -13,270 +13,277 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// prettier-ignore
|
||||
const ExpertEncoding = [
|
||||
'', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
|
||||
'', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
|
||||
'space', 'exclamsmall', 'Hungarumlautsmall', '', 'dollaroldstyle',
|
||||
'dollarsuperior', 'ampersandsmall', 'Acutesmall', 'parenleftsuperior',
|
||||
'parenrightsuperior', 'twodotenleader', 'onedotenleader', 'comma',
|
||||
'hyphen', 'period', 'fraction', 'zerooldstyle', 'oneoldstyle',
|
||||
'twooldstyle', 'threeoldstyle', 'fouroldstyle', 'fiveoldstyle',
|
||||
'sixoldstyle', 'sevenoldstyle', 'eightoldstyle', 'nineoldstyle', 'colon',
|
||||
'semicolon', 'commasuperior', 'threequartersemdash', 'periodsuperior',
|
||||
'questionsmall', '', 'asuperior', 'bsuperior', 'centsuperior', 'dsuperior',
|
||||
'esuperior', '', '', '', 'isuperior', '', '', 'lsuperior', 'msuperior',
|
||||
'nsuperior', 'osuperior', '', '', 'rsuperior', 'ssuperior', 'tsuperior',
|
||||
'', 'ff', 'fi', 'fl', 'ffi', 'ffl', 'parenleftinferior', '',
|
||||
'parenrightinferior', 'Circumflexsmall', 'hyphensuperior', 'Gravesmall',
|
||||
'Asmall', 'Bsmall', 'Csmall', 'Dsmall', 'Esmall', 'Fsmall', 'Gsmall',
|
||||
'Hsmall', 'Ismall', 'Jsmall', 'Ksmall', 'Lsmall', 'Msmall', 'Nsmall',
|
||||
'Osmall', 'Psmall', 'Qsmall', 'Rsmall', 'Ssmall', 'Tsmall', 'Usmall',
|
||||
'Vsmall', 'Wsmall', 'Xsmall', 'Ysmall', 'Zsmall', 'colonmonetary',
|
||||
'onefitted', 'rupiah', 'Tildesmall', '', '', '', '', '', '', '', '', '',
|
||||
'', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
|
||||
'', '', '', '', '', '', 'exclamdownsmall', 'centoldstyle', 'Lslashsmall',
|
||||
'', '', 'Scaronsmall', 'Zcaronsmall', 'Dieresissmall', 'Brevesmall',
|
||||
'Caronsmall', '', 'Dotaccentsmall', '', '', 'Macronsmall', '', '',
|
||||
'figuredash', 'hypheninferior', '', '', 'Ogoneksmall', 'Ringsmall',
|
||||
'Cedillasmall', '', '', '', 'onequarter', 'onehalf', 'threequarters',
|
||||
'questiondownsmall', 'oneeighth', 'threeeighths', 'fiveeighths',
|
||||
'seveneighths', 'onethird', 'twothirds', '', '', 'zerosuperior',
|
||||
'onesuperior', 'twosuperior', 'threesuperior', 'foursuperior',
|
||||
'fivesuperior', 'sixsuperior', 'sevensuperior', 'eightsuperior',
|
||||
'ninesuperior', 'zeroinferior', 'oneinferior', 'twoinferior',
|
||||
'threeinferior', 'fourinferior', 'fiveinferior', 'sixinferior',
|
||||
'seveninferior', 'eightinferior', 'nineinferior', 'centinferior',
|
||||
'dollarinferior', 'periodinferior', 'commainferior', 'Agravesmall',
|
||||
'Aacutesmall', 'Acircumflexsmall', 'Atildesmall', 'Adieresissmall',
|
||||
'Aringsmall', 'AEsmall', 'Ccedillasmall', 'Egravesmall', 'Eacutesmall',
|
||||
'Ecircumflexsmall', 'Edieresissmall', 'Igravesmall', 'Iacutesmall',
|
||||
'Icircumflexsmall', 'Idieresissmall', 'Ethsmall', 'Ntildesmall',
|
||||
'Ogravesmall', 'Oacutesmall', 'Ocircumflexsmall', 'Otildesmall',
|
||||
'Odieresissmall', 'OEsmall', 'Oslashsmall', 'Ugravesmall', 'Uacutesmall',
|
||||
'Ucircumflexsmall', 'Udieresissmall', 'Yacutesmall', 'Thornsmall',
|
||||
'Ydieresissmall'];
|
||||
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
|
||||
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
|
||||
"space", "exclamsmall", "Hungarumlautsmall", "", "dollaroldstyle",
|
||||
"dollarsuperior", "ampersandsmall", "Acutesmall", "parenleftsuperior",
|
||||
"parenrightsuperior", "twodotenleader", "onedotenleader", "comma",
|
||||
"hyphen", "period", "fraction", "zerooldstyle", "oneoldstyle",
|
||||
"twooldstyle", "threeoldstyle", "fouroldstyle", "fiveoldstyle",
|
||||
"sixoldstyle", "sevenoldstyle", "eightoldstyle", "nineoldstyle", "colon",
|
||||
"semicolon", "commasuperior", "threequartersemdash", "periodsuperior",
|
||||
"questionsmall", "", "asuperior", "bsuperior", "centsuperior", "dsuperior",
|
||||
"esuperior", "", "", "", "isuperior", "", "", "lsuperior", "msuperior",
|
||||
"nsuperior", "osuperior", "", "", "rsuperior", "ssuperior", "tsuperior",
|
||||
"", "ff", "fi", "fl", "ffi", "ffl", "parenleftinferior", "",
|
||||
"parenrightinferior", "Circumflexsmall", "hyphensuperior", "Gravesmall",
|
||||
"Asmall", "Bsmall", "Csmall", "Dsmall", "Esmall", "Fsmall", "Gsmall",
|
||||
"Hsmall", "Ismall", "Jsmall", "Ksmall", "Lsmall", "Msmall", "Nsmall",
|
||||
"Osmall", "Psmall", "Qsmall", "Rsmall", "Ssmall", "Tsmall", "Usmall",
|
||||
"Vsmall", "Wsmall", "Xsmall", "Ysmall", "Zsmall", "colonmonetary",
|
||||
"onefitted", "rupiah", "Tildesmall", "", "", "", "", "", "", "", "", "",
|
||||
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
|
||||
"", "", "", "", "", "", "exclamdownsmall", "centoldstyle", "Lslashsmall",
|
||||
"", "", "Scaronsmall", "Zcaronsmall", "Dieresissmall", "Brevesmall",
|
||||
"Caronsmall", "", "Dotaccentsmall", "", "", "Macronsmall", "", "",
|
||||
"figuredash", "hypheninferior", "", "", "Ogoneksmall", "Ringsmall",
|
||||
"Cedillasmall", "", "", "", "onequarter", "onehalf", "threequarters",
|
||||
"questiondownsmall", "oneeighth", "threeeighths", "fiveeighths",
|
||||
"seveneighths", "onethird", "twothirds", "", "", "zerosuperior",
|
||||
"onesuperior", "twosuperior", "threesuperior", "foursuperior",
|
||||
"fivesuperior", "sixsuperior", "sevensuperior", "eightsuperior",
|
||||
"ninesuperior", "zeroinferior", "oneinferior", "twoinferior",
|
||||
"threeinferior", "fourinferior", "fiveinferior", "sixinferior",
|
||||
"seveninferior", "eightinferior", "nineinferior", "centinferior",
|
||||
"dollarinferior", "periodinferior", "commainferior", "Agravesmall",
|
||||
"Aacutesmall", "Acircumflexsmall", "Atildesmall", "Adieresissmall",
|
||||
"Aringsmall", "AEsmall", "Ccedillasmall", "Egravesmall", "Eacutesmall",
|
||||
"Ecircumflexsmall", "Edieresissmall", "Igravesmall", "Iacutesmall",
|
||||
"Icircumflexsmall", "Idieresissmall", "Ethsmall", "Ntildesmall",
|
||||
"Ogravesmall", "Oacutesmall", "Ocircumflexsmall", "Otildesmall",
|
||||
"Odieresissmall", "OEsmall", "Oslashsmall", "Ugravesmall", "Uacutesmall",
|
||||
"Ucircumflexsmall", "Udieresissmall", "Yacutesmall", "Thornsmall",
|
||||
"Ydieresissmall"];
|
||||
|
||||
// prettier-ignore
|
||||
const MacExpertEncoding = [
|
||||
'', '', '', '', '', '', '', '', '', '', '', '', '', '',
|
||||
'', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
|
||||
'space', 'exclamsmall', 'Hungarumlautsmall', 'centoldstyle',
|
||||
'dollaroldstyle', 'dollarsuperior', 'ampersandsmall', 'Acutesmall',
|
||||
'parenleftsuperior', 'parenrightsuperior', 'twodotenleader',
|
||||
'onedotenleader', 'comma', 'hyphen', 'period', 'fraction', 'zerooldstyle',
|
||||
'oneoldstyle', 'twooldstyle', 'threeoldstyle', 'fouroldstyle',
|
||||
'fiveoldstyle', 'sixoldstyle', 'sevenoldstyle', 'eightoldstyle',
|
||||
'nineoldstyle', 'colon', 'semicolon', '', 'threequartersemdash', '',
|
||||
'questionsmall', '', '', '', '', 'Ethsmall', '', '', 'onequarter',
|
||||
'onehalf', 'threequarters', 'oneeighth', 'threeeighths', 'fiveeighths',
|
||||
'seveneighths', 'onethird', 'twothirds', '', '', '', '', '', '', 'ff',
|
||||
'fi', 'fl', 'ffi', 'ffl', 'parenleftinferior', '', 'parenrightinferior',
|
||||
'Circumflexsmall', 'hypheninferior', 'Gravesmall', 'Asmall', 'Bsmall',
|
||||
'Csmall', 'Dsmall', 'Esmall', 'Fsmall', 'Gsmall', 'Hsmall', 'Ismall',
|
||||
'Jsmall', 'Ksmall', 'Lsmall', 'Msmall', 'Nsmall', 'Osmall', 'Psmall',
|
||||
'Qsmall', 'Rsmall', 'Ssmall', 'Tsmall', 'Usmall', 'Vsmall', 'Wsmall',
|
||||
'Xsmall', 'Ysmall', 'Zsmall', 'colonmonetary', 'onefitted', 'rupiah',
|
||||
'Tildesmall', '', '', 'asuperior', 'centsuperior', '', '', '', '',
|
||||
'Aacutesmall', 'Agravesmall', 'Acircumflexsmall', 'Adieresissmall',
|
||||
'Atildesmall', 'Aringsmall', 'Ccedillasmall', 'Eacutesmall', 'Egravesmall',
|
||||
'Ecircumflexsmall', 'Edieresissmall', 'Iacutesmall', 'Igravesmall',
|
||||
'Icircumflexsmall', 'Idieresissmall', 'Ntildesmall', 'Oacutesmall',
|
||||
'Ogravesmall', 'Ocircumflexsmall', 'Odieresissmall', 'Otildesmall',
|
||||
'Uacutesmall', 'Ugravesmall', 'Ucircumflexsmall', 'Udieresissmall', '',
|
||||
'eightsuperior', 'fourinferior', 'threeinferior', 'sixinferior',
|
||||
'eightinferior', 'seveninferior', 'Scaronsmall', '', 'centinferior',
|
||||
'twoinferior', '', 'Dieresissmall', '', 'Caronsmall', 'osuperior',
|
||||
'fiveinferior', '', 'commainferior', 'periodinferior', 'Yacutesmall', '',
|
||||
'dollarinferior', '', '', 'Thornsmall', '', 'nineinferior', 'zeroinferior',
|
||||
'Zcaronsmall', 'AEsmall', 'Oslashsmall', 'questiondownsmall',
|
||||
'oneinferior', 'Lslashsmall', '', '', '', '', '', '', 'Cedillasmall', '',
|
||||
'', '', '', '', 'OEsmall', 'figuredash', 'hyphensuperior', '', '', '', '',
|
||||
'exclamdownsmall', '', 'Ydieresissmall', '', 'onesuperior', 'twosuperior',
|
||||
'threesuperior', 'foursuperior', 'fivesuperior', 'sixsuperior',
|
||||
'sevensuperior', 'ninesuperior', 'zerosuperior', '', 'esuperior',
|
||||
'rsuperior', 'tsuperior', '', '', 'isuperior', 'ssuperior', 'dsuperior',
|
||||
'', '', '', '', '', 'lsuperior', 'Ogoneksmall', 'Brevesmall',
|
||||
'Macronsmall', 'bsuperior', 'nsuperior', 'msuperior', 'commasuperior',
|
||||
'periodsuperior', 'Dotaccentsmall', 'Ringsmall', '', '', '', ''];
|
||||
"", "", "", "", "", "", "", "", "", "", "", "", "", "",
|
||||
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
|
||||
"space", "exclamsmall", "Hungarumlautsmall", "centoldstyle",
|
||||
"dollaroldstyle", "dollarsuperior", "ampersandsmall", "Acutesmall",
|
||||
"parenleftsuperior", "parenrightsuperior", "twodotenleader",
|
||||
"onedotenleader", "comma", "hyphen", "period", "fraction", "zerooldstyle",
|
||||
"oneoldstyle", "twooldstyle", "threeoldstyle", "fouroldstyle",
|
||||
"fiveoldstyle", "sixoldstyle", "sevenoldstyle", "eightoldstyle",
|
||||
"nineoldstyle", "colon", "semicolon", "", "threequartersemdash", "",
|
||||
"questionsmall", "", "", "", "", "Ethsmall", "", "", "onequarter",
|
||||
"onehalf", "threequarters", "oneeighth", "threeeighths", "fiveeighths",
|
||||
"seveneighths", "onethird", "twothirds", "", "", "", "", "", "", "ff",
|
||||
"fi", "fl", "ffi", "ffl", "parenleftinferior", "", "parenrightinferior",
|
||||
"Circumflexsmall", "hypheninferior", "Gravesmall", "Asmall", "Bsmall",
|
||||
"Csmall", "Dsmall", "Esmall", "Fsmall", "Gsmall", "Hsmall", "Ismall",
|
||||
"Jsmall", "Ksmall", "Lsmall", "Msmall", "Nsmall", "Osmall", "Psmall",
|
||||
"Qsmall", "Rsmall", "Ssmall", "Tsmall", "Usmall", "Vsmall", "Wsmall",
|
||||
"Xsmall", "Ysmall", "Zsmall", "colonmonetary", "onefitted", "rupiah",
|
||||
"Tildesmall", "", "", "asuperior", "centsuperior", "", "", "", "",
|
||||
"Aacutesmall", "Agravesmall", "Acircumflexsmall", "Adieresissmall",
|
||||
"Atildesmall", "Aringsmall", "Ccedillasmall", "Eacutesmall", "Egravesmall",
|
||||
"Ecircumflexsmall", "Edieresissmall", "Iacutesmall", "Igravesmall",
|
||||
"Icircumflexsmall", "Idieresissmall", "Ntildesmall", "Oacutesmall",
|
||||
"Ogravesmall", "Ocircumflexsmall", "Odieresissmall", "Otildesmall",
|
||||
"Uacutesmall", "Ugravesmall", "Ucircumflexsmall", "Udieresissmall", "",
|
||||
"eightsuperior", "fourinferior", "threeinferior", "sixinferior",
|
||||
"eightinferior", "seveninferior", "Scaronsmall", "", "centinferior",
|
||||
"twoinferior", "", "Dieresissmall", "", "Caronsmall", "osuperior",
|
||||
"fiveinferior", "", "commainferior", "periodinferior", "Yacutesmall", "",
|
||||
"dollarinferior", "", "", "Thornsmall", "", "nineinferior", "zeroinferior",
|
||||
"Zcaronsmall", "AEsmall", "Oslashsmall", "questiondownsmall",
|
||||
"oneinferior", "Lslashsmall", "", "", "", "", "", "", "Cedillasmall", "",
|
||||
"", "", "", "", "OEsmall", "figuredash", "hyphensuperior", "", "", "", "",
|
||||
"exclamdownsmall", "", "Ydieresissmall", "", "onesuperior", "twosuperior",
|
||||
"threesuperior", "foursuperior", "fivesuperior", "sixsuperior",
|
||||
"sevensuperior", "ninesuperior", "zerosuperior", "", "esuperior",
|
||||
"rsuperior", "tsuperior", "", "", "isuperior", "ssuperior", "dsuperior",
|
||||
"", "", "", "", "", "lsuperior", "Ogoneksmall", "Brevesmall",
|
||||
"Macronsmall", "bsuperior", "nsuperior", "msuperior", "commasuperior",
|
||||
"periodsuperior", "Dotaccentsmall", "Ringsmall", "", "", "", ""];
|
||||
|
||||
// prettier-ignore
|
||||
const MacRomanEncoding = [
|
||||
'', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
|
||||
'', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
|
||||
'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent',
|
||||
'ampersand', 'quotesingle', 'parenleft', 'parenright', 'asterisk', 'plus',
|
||||
'comma', 'hyphen', 'period', 'slash', 'zero', 'one', 'two', 'three',
|
||||
'four', 'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon',
|
||||
'less', 'equal', 'greater', 'question', 'at', 'A', 'B', 'C', 'D', 'E', 'F',
|
||||
'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U',
|
||||
'V', 'W', 'X', 'Y', 'Z', 'bracketleft', 'backslash', 'bracketright',
|
||||
'asciicircum', 'underscore', 'grave', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
|
||||
'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
|
||||
'w', 'x', 'y', 'z', 'braceleft', 'bar', 'braceright', 'asciitilde', '',
|
||||
'Adieresis', 'Aring', 'Ccedilla', 'Eacute', 'Ntilde', 'Odieresis',
|
||||
'Udieresis', 'aacute', 'agrave', 'acircumflex', 'adieresis', 'atilde',
|
||||
'aring', 'ccedilla', 'eacute', 'egrave', 'ecircumflex', 'edieresis',
|
||||
'iacute', 'igrave', 'icircumflex', 'idieresis', 'ntilde', 'oacute',
|
||||
'ograve', 'ocircumflex', 'odieresis', 'otilde', 'uacute', 'ugrave',
|
||||
'ucircumflex', 'udieresis', 'dagger', 'degree', 'cent', 'sterling',
|
||||
'section', 'bullet', 'paragraph', 'germandbls', 'registered', 'copyright',
|
||||
'trademark', 'acute', 'dieresis', 'notequal', 'AE', 'Oslash', 'infinity',
|
||||
'plusminus', 'lessequal', 'greaterequal', 'yen', 'mu', 'partialdiff',
|
||||
'summation', 'product', 'pi', 'integral', 'ordfeminine', 'ordmasculine',
|
||||
'Omega', 'ae', 'oslash', 'questiondown', 'exclamdown', 'logicalnot',
|
||||
'radical', 'florin', 'approxequal', 'Delta', 'guillemotleft',
|
||||
'guillemotright', 'ellipsis', 'space', 'Agrave', 'Atilde', 'Otilde', 'OE',
|
||||
'oe', 'endash', 'emdash', 'quotedblleft', 'quotedblright', 'quoteleft',
|
||||
'quoteright', 'divide', 'lozenge', 'ydieresis', 'Ydieresis', 'fraction',
|
||||
'currency', 'guilsinglleft', 'guilsinglright', 'fi', 'fl', 'daggerdbl',
|
||||
'periodcentered', 'quotesinglbase', 'quotedblbase', 'perthousand',
|
||||
'Acircumflex', 'Ecircumflex', 'Aacute', 'Edieresis', 'Egrave', 'Iacute',
|
||||
'Icircumflex', 'Idieresis', 'Igrave', 'Oacute', 'Ocircumflex', 'apple',
|
||||
'Ograve', 'Uacute', 'Ucircumflex', 'Ugrave', 'dotlessi', 'circumflex',
|
||||
'tilde', 'macron', 'breve', 'dotaccent', 'ring', 'cedilla', 'hungarumlaut',
|
||||
'ogonek', 'caron'];
|
||||
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
|
||||
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
|
||||
"space", "exclam", "quotedbl", "numbersign", "dollar", "percent",
|
||||
"ampersand", "quotesingle", "parenleft", "parenright", "asterisk", "plus",
|
||||
"comma", "hyphen", "period", "slash", "zero", "one", "two", "three",
|
||||
"four", "five", "six", "seven", "eight", "nine", "colon", "semicolon",
|
||||
"less", "equal", "greater", "question", "at", "A", "B", "C", "D", "E", "F",
|
||||
"G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U",
|
||||
"V", "W", "X", "Y", "Z", "bracketleft", "backslash", "bracketright",
|
||||
"asciicircum", "underscore", "grave", "a", "b", "c", "d", "e", "f", "g",
|
||||
"h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v",
|
||||
"w", "x", "y", "z", "braceleft", "bar", "braceright", "asciitilde", "",
|
||||
"Adieresis", "Aring", "Ccedilla", "Eacute", "Ntilde", "Odieresis",
|
||||
"Udieresis", "aacute", "agrave", "acircumflex", "adieresis", "atilde",
|
||||
"aring", "ccedilla", "eacute", "egrave", "ecircumflex", "edieresis",
|
||||
"iacute", "igrave", "icircumflex", "idieresis", "ntilde", "oacute",
|
||||
"ograve", "ocircumflex", "odieresis", "otilde", "uacute", "ugrave",
|
||||
"ucircumflex", "udieresis", "dagger", "degree", "cent", "sterling",
|
||||
"section", "bullet", "paragraph", "germandbls", "registered", "copyright",
|
||||
"trademark", "acute", "dieresis", "notequal", "AE", "Oslash", "infinity",
|
||||
"plusminus", "lessequal", "greaterequal", "yen", "mu", "partialdiff",
|
||||
"summation", "product", "pi", "integral", "ordfeminine", "ordmasculine",
|
||||
"Omega", "ae", "oslash", "questiondown", "exclamdown", "logicalnot",
|
||||
"radical", "florin", "approxequal", "Delta", "guillemotleft",
|
||||
"guillemotright", "ellipsis", "space", "Agrave", "Atilde", "Otilde", "OE",
|
||||
"oe", "endash", "emdash", "quotedblleft", "quotedblright", "quoteleft",
|
||||
"quoteright", "divide", "lozenge", "ydieresis", "Ydieresis", "fraction",
|
||||
"currency", "guilsinglleft", "guilsinglright", "fi", "fl", "daggerdbl",
|
||||
"periodcentered", "quotesinglbase", "quotedblbase", "perthousand",
|
||||
"Acircumflex", "Ecircumflex", "Aacute", "Edieresis", "Egrave", "Iacute",
|
||||
"Icircumflex", "Idieresis", "Igrave", "Oacute", "Ocircumflex", "apple",
|
||||
"Ograve", "Uacute", "Ucircumflex", "Ugrave", "dotlessi", "circumflex",
|
||||
"tilde", "macron", "breve", "dotaccent", "ring", "cedilla", "hungarumlaut",
|
||||
"ogonek", "caron"];
|
||||
|
||||
// prettier-ignore
|
||||
const StandardEncoding = [
|
||||
'', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
|
||||
'', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
|
||||
'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent',
|
||||
'ampersand', 'quoteright', 'parenleft', 'parenright', 'asterisk', 'plus',
|
||||
'comma', 'hyphen', 'period', 'slash', 'zero', 'one', 'two', 'three',
|
||||
'four', 'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon',
|
||||
'less', 'equal', 'greater', 'question', 'at', 'A', 'B', 'C', 'D', 'E', 'F',
|
||||
'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U',
|
||||
'V', 'W', 'X', 'Y', 'Z', 'bracketleft', 'backslash', 'bracketright',
|
||||
'asciicircum', 'underscore', 'quoteleft', 'a', 'b', 'c', 'd', 'e', 'f',
|
||||
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u',
|
||||
'v', 'w', 'x', 'y', 'z', 'braceleft', 'bar', 'braceright', 'asciitilde',
|
||||
'', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
|
||||
'', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 'exclamdown',
|
||||
'cent', 'sterling', 'fraction', 'yen', 'florin', 'section', 'currency',
|
||||
'quotesingle', 'quotedblleft', 'guillemotleft', 'guilsinglleft',
|
||||
'guilsinglright', 'fi', 'fl', '', 'endash', 'dagger', 'daggerdbl',
|
||||
'periodcentered', '', 'paragraph', 'bullet', 'quotesinglbase',
|
||||
'quotedblbase', 'quotedblright', 'guillemotright', 'ellipsis',
|
||||
'perthousand', '', 'questiondown', '', 'grave', 'acute', 'circumflex',
|
||||
'tilde', 'macron', 'breve', 'dotaccent', 'dieresis', '', 'ring', 'cedilla',
|
||||
'', 'hungarumlaut', 'ogonek', 'caron', 'emdash', '', '', '', '', '', '',
|
||||
'', '', '', '', '', '', '', '', '', '', 'AE', '', 'ordfeminine', '', '',
|
||||
'', '', 'Lslash', 'Oslash', 'OE', 'ordmasculine', '', '', '', '', '', 'ae',
|
||||
'', '', '', 'dotlessi', '', '', 'lslash', 'oslash', 'oe', 'germandbls', '',
|
||||
'', '', ''];
|
||||
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
|
||||
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
|
||||
"space", "exclam", "quotedbl", "numbersign", "dollar", "percent",
|
||||
"ampersand", "quoteright", "parenleft", "parenright", "asterisk", "plus",
|
||||
"comma", "hyphen", "period", "slash", "zero", "one", "two", "three",
|
||||
"four", "five", "six", "seven", "eight", "nine", "colon", "semicolon",
|
||||
"less", "equal", "greater", "question", "at", "A", "B", "C", "D", "E", "F",
|
||||
"G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U",
|
||||
"V", "W", "X", "Y", "Z", "bracketleft", "backslash", "bracketright",
|
||||
"asciicircum", "underscore", "quoteleft", "a", "b", "c", "d", "e", "f",
|
||||
"g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u",
|
||||
"v", "w", "x", "y", "z", "braceleft", "bar", "braceright", "asciitilde",
|
||||
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
|
||||
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "exclamdown",
|
||||
"cent", "sterling", "fraction", "yen", "florin", "section", "currency",
|
||||
"quotesingle", "quotedblleft", "guillemotleft", "guilsinglleft",
|
||||
"guilsinglright", "fi", "fl", "", "endash", "dagger", "daggerdbl",
|
||||
"periodcentered", "", "paragraph", "bullet", "quotesinglbase",
|
||||
"quotedblbase", "quotedblright", "guillemotright", "ellipsis",
|
||||
"perthousand", "", "questiondown", "", "grave", "acute", "circumflex",
|
||||
"tilde", "macron", "breve", "dotaccent", "dieresis", "", "ring", "cedilla",
|
||||
"", "hungarumlaut", "ogonek", "caron", "emdash", "", "", "", "", "", "",
|
||||
"", "", "", "", "", "", "", "", "", "", "AE", "", "ordfeminine", "", "",
|
||||
"", "", "Lslash", "Oslash", "OE", "ordmasculine", "", "", "", "", "", "ae",
|
||||
"", "", "", "dotlessi", "", "", "lslash", "oslash", "oe", "germandbls", "",
|
||||
"", "", ""];
|
||||
|
||||
// prettier-ignore
|
||||
const WinAnsiEncoding = [
|
||||
'', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
|
||||
'', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
|
||||
'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent',
|
||||
'ampersand', 'quotesingle', 'parenleft', 'parenright', 'asterisk', 'plus',
|
||||
'comma', 'hyphen', 'period', 'slash', 'zero', 'one', 'two', 'three',
|
||||
'four', 'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon',
|
||||
'less', 'equal', 'greater', 'question', 'at', 'A', 'B', 'C', 'D', 'E', 'F',
|
||||
'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U',
|
||||
'V', 'W', 'X', 'Y', 'Z', 'bracketleft', 'backslash', 'bracketright',
|
||||
'asciicircum', 'underscore', 'grave', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
|
||||
'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
|
||||
'w', 'x', 'y', 'z', 'braceleft', 'bar', 'braceright', 'asciitilde',
|
||||
'bullet', 'Euro', 'bullet', 'quotesinglbase', 'florin', 'quotedblbase',
|
||||
'ellipsis', 'dagger', 'daggerdbl', 'circumflex', 'perthousand', 'Scaron',
|
||||
'guilsinglleft', 'OE', 'bullet', 'Zcaron', 'bullet', 'bullet', 'quoteleft',
|
||||
'quoteright', 'quotedblleft', 'quotedblright', 'bullet', 'endash',
|
||||
'emdash', 'tilde', 'trademark', 'scaron', 'guilsinglright', 'oe', 'bullet',
|
||||
'zcaron', 'Ydieresis', 'space', 'exclamdown', 'cent', 'sterling',
|
||||
'currency', 'yen', 'brokenbar', 'section', 'dieresis', 'copyright',
|
||||
'ordfeminine', 'guillemotleft', 'logicalnot', 'hyphen', 'registered',
|
||||
'macron', 'degree', 'plusminus', 'twosuperior', 'threesuperior', 'acute',
|
||||
'mu', 'paragraph', 'periodcentered', 'cedilla', 'onesuperior',
|
||||
'ordmasculine', 'guillemotright', 'onequarter', 'onehalf', 'threequarters',
|
||||
'questiondown', 'Agrave', 'Aacute', 'Acircumflex', 'Atilde', 'Adieresis',
|
||||
'Aring', 'AE', 'Ccedilla', 'Egrave', 'Eacute', 'Ecircumflex', 'Edieresis',
|
||||
'Igrave', 'Iacute', 'Icircumflex', 'Idieresis', 'Eth', 'Ntilde', 'Ograve',
|
||||
'Oacute', 'Ocircumflex', 'Otilde', 'Odieresis', 'multiply', 'Oslash',
|
||||
'Ugrave', 'Uacute', 'Ucircumflex', 'Udieresis', 'Yacute', 'Thorn',
|
||||
'germandbls', 'agrave', 'aacute', 'acircumflex', 'atilde', 'adieresis',
|
||||
'aring', 'ae', 'ccedilla', 'egrave', 'eacute', 'ecircumflex', 'edieresis',
|
||||
'igrave', 'iacute', 'icircumflex', 'idieresis', 'eth', 'ntilde', 'ograve',
|
||||
'oacute', 'ocircumflex', 'otilde', 'odieresis', 'divide', 'oslash',
|
||||
'ugrave', 'uacute', 'ucircumflex', 'udieresis', 'yacute', 'thorn',
|
||||
'ydieresis'];
|
||||
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
|
||||
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
|
||||
"space", "exclam", "quotedbl", "numbersign", "dollar", "percent",
|
||||
"ampersand", "quotesingle", "parenleft", "parenright", "asterisk", "plus",
|
||||
"comma", "hyphen", "period", "slash", "zero", "one", "two", "three",
|
||||
"four", "five", "six", "seven", "eight", "nine", "colon", "semicolon",
|
||||
"less", "equal", "greater", "question", "at", "A", "B", "C", "D", "E", "F",
|
||||
"G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U",
|
||||
"V", "W", "X", "Y", "Z", "bracketleft", "backslash", "bracketright",
|
||||
"asciicircum", "underscore", "grave", "a", "b", "c", "d", "e", "f", "g",
|
||||
"h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v",
|
||||
"w", "x", "y", "z", "braceleft", "bar", "braceright", "asciitilde",
|
||||
"bullet", "Euro", "bullet", "quotesinglbase", "florin", "quotedblbase",
|
||||
"ellipsis", "dagger", "daggerdbl", "circumflex", "perthousand", "Scaron",
|
||||
"guilsinglleft", "OE", "bullet", "Zcaron", "bullet", "bullet", "quoteleft",
|
||||
"quoteright", "quotedblleft", "quotedblright", "bullet", "endash",
|
||||
"emdash", "tilde", "trademark", "scaron", "guilsinglright", "oe", "bullet",
|
||||
"zcaron", "Ydieresis", "space", "exclamdown", "cent", "sterling",
|
||||
"currency", "yen", "brokenbar", "section", "dieresis", "copyright",
|
||||
"ordfeminine", "guillemotleft", "logicalnot", "hyphen", "registered",
|
||||
"macron", "degree", "plusminus", "twosuperior", "threesuperior", "acute",
|
||||
"mu", "paragraph", "periodcentered", "cedilla", "onesuperior",
|
||||
"ordmasculine", "guillemotright", "onequarter", "onehalf", "threequarters",
|
||||
"questiondown", "Agrave", "Aacute", "Acircumflex", "Atilde", "Adieresis",
|
||||
"Aring", "AE", "Ccedilla", "Egrave", "Eacute", "Ecircumflex", "Edieresis",
|
||||
"Igrave", "Iacute", "Icircumflex", "Idieresis", "Eth", "Ntilde", "Ograve",
|
||||
"Oacute", "Ocircumflex", "Otilde", "Odieresis", "multiply", "Oslash",
|
||||
"Ugrave", "Uacute", "Ucircumflex", "Udieresis", "Yacute", "Thorn",
|
||||
"germandbls", "agrave", "aacute", "acircumflex", "atilde", "adieresis",
|
||||
"aring", "ae", "ccedilla", "egrave", "eacute", "ecircumflex", "edieresis",
|
||||
"igrave", "iacute", "icircumflex", "idieresis", "eth", "ntilde", "ograve",
|
||||
"oacute", "ocircumflex", "otilde", "odieresis", "divide", "oslash",
|
||||
"ugrave", "uacute", "ucircumflex", "udieresis", "yacute", "thorn",
|
||||
"ydieresis"];
|
||||
|
||||
// prettier-ignore
|
||||
const SymbolSetEncoding = [
|
||||
'', '', '', '', '', '', '', '', '', '', '', '', '', '',
|
||||
'', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
|
||||
'space', 'exclam', 'universal', 'numbersign', 'existential', 'percent',
|
||||
'ampersand', 'suchthat', 'parenleft', 'parenright', 'asteriskmath', 'plus',
|
||||
'comma', 'minus', 'period', 'slash', 'zero', 'one', 'two', 'three', 'four',
|
||||
'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon', 'less',
|
||||
'equal', 'greater', 'question', 'congruent', 'Alpha', 'Beta', 'Chi',
|
||||
'Delta', 'Epsilon', 'Phi', 'Gamma', 'Eta', 'Iota', 'theta1', 'Kappa',
|
||||
'Lambda', 'Mu', 'Nu', 'Omicron', 'Pi', 'Theta', 'Rho', 'Sigma', 'Tau',
|
||||
'Upsilon', 'sigma1', 'Omega', 'Xi', 'Psi', 'Zeta', 'bracketleft',
|
||||
'therefore', 'bracketright', 'perpendicular', 'underscore', 'radicalex',
|
||||
'alpha', 'beta', 'chi', 'delta', 'epsilon', 'phi', 'gamma', 'eta', 'iota',
|
||||
'phi1', 'kappa', 'lambda', 'mu', 'nu', 'omicron', 'pi', 'theta', 'rho',
|
||||
'sigma', 'tau', 'upsilon', 'omega1', 'omega', 'xi', 'psi', 'zeta',
|
||||
'braceleft', 'bar', 'braceright', 'similar', '', '', '', '', '', '', '',
|
||||
'', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
|
||||
'', '', '', '', '', '', '', 'Euro', 'Upsilon1', 'minute', 'lessequal',
|
||||
'fraction', 'infinity', 'florin', 'club', 'diamond', 'heart', 'spade',
|
||||
'arrowboth', 'arrowleft', 'arrowup', 'arrowright', 'arrowdown', 'degree',
|
||||
'plusminus', 'second', 'greaterequal', 'multiply', 'proportional',
|
||||
'partialdiff', 'bullet', 'divide', 'notequal', 'equivalence',
|
||||
'approxequal', 'ellipsis', 'arrowvertex', 'arrowhorizex', 'carriagereturn',
|
||||
'aleph', 'Ifraktur', 'Rfraktur', 'weierstrass', 'circlemultiply',
|
||||
'circleplus', 'emptyset', 'intersection', 'union', 'propersuperset',
|
||||
'reflexsuperset', 'notsubset', 'propersubset', 'reflexsubset', 'element',
|
||||
'notelement', 'angle', 'gradient', 'registerserif', 'copyrightserif',
|
||||
'trademarkserif', 'product', 'radical', 'dotmath', 'logicalnot',
|
||||
'logicaland', 'logicalor', 'arrowdblboth', 'arrowdblleft', 'arrowdblup',
|
||||
'arrowdblright', 'arrowdbldown', 'lozenge', 'angleleft', 'registersans',
|
||||
'copyrightsans', 'trademarksans', 'summation', 'parenlefttp',
|
||||
'parenleftex', 'parenleftbt', 'bracketlefttp', 'bracketleftex',
|
||||
'bracketleftbt', 'bracelefttp', 'braceleftmid', 'braceleftbt', 'braceex',
|
||||
'', 'angleright', 'integral', 'integraltp', 'integralex', 'integralbt',
|
||||
'parenrighttp', 'parenrightex', 'parenrightbt', 'bracketrighttp',
|
||||
'bracketrightex', 'bracketrightbt', 'bracerighttp', 'bracerightmid',
|
||||
'bracerightbt', ''];
|
||||
"", "", "", "", "", "", "", "", "", "", "", "", "", "",
|
||||
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
|
||||
"space", "exclam", "universal", "numbersign", "existential", "percent",
|
||||
"ampersand", "suchthat", "parenleft", "parenright", "asteriskmath", "plus",
|
||||
"comma", "minus", "period", "slash", "zero", "one", "two", "three", "four",
|
||||
"five", "six", "seven", "eight", "nine", "colon", "semicolon", "less",
|
||||
"equal", "greater", "question", "congruent", "Alpha", "Beta", "Chi",
|
||||
"Delta", "Epsilon", "Phi", "Gamma", "Eta", "Iota", "theta1", "Kappa",
|
||||
"Lambda", "Mu", "Nu", "Omicron", "Pi", "Theta", "Rho", "Sigma", "Tau",
|
||||
"Upsilon", "sigma1", "Omega", "Xi", "Psi", "Zeta", "bracketleft",
|
||||
"therefore", "bracketright", "perpendicular", "underscore", "radicalex",
|
||||
"alpha", "beta", "chi", "delta", "epsilon", "phi", "gamma", "eta", "iota",
|
||||
"phi1", "kappa", "lambda", "mu", "nu", "omicron", "pi", "theta", "rho",
|
||||
"sigma", "tau", "upsilon", "omega1", "omega", "xi", "psi", "zeta",
|
||||
"braceleft", "bar", "braceright", "similar", "", "", "", "", "", "", "",
|
||||
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
|
||||
"", "", "", "", "", "", "", "Euro", "Upsilon1", "minute", "lessequal",
|
||||
"fraction", "infinity", "florin", "club", "diamond", "heart", "spade",
|
||||
"arrowboth", "arrowleft", "arrowup", "arrowright", "arrowdown", "degree",
|
||||
"plusminus", "second", "greaterequal", "multiply", "proportional",
|
||||
"partialdiff", "bullet", "divide", "notequal", "equivalence",
|
||||
"approxequal", "ellipsis", "arrowvertex", "arrowhorizex", "carriagereturn",
|
||||
"aleph", "Ifraktur", "Rfraktur", "weierstrass", "circlemultiply",
|
||||
"circleplus", "emptyset", "intersection", "union", "propersuperset",
|
||||
"reflexsuperset", "notsubset", "propersubset", "reflexsubset", "element",
|
||||
"notelement", "angle", "gradient", "registerserif", "copyrightserif",
|
||||
"trademarkserif", "product", "radical", "dotmath", "logicalnot",
|
||||
"logicaland", "logicalor", "arrowdblboth", "arrowdblleft", "arrowdblup",
|
||||
"arrowdblright", "arrowdbldown", "lozenge", "angleleft", "registersans",
|
||||
"copyrightsans", "trademarksans", "summation", "parenlefttp",
|
||||
"parenleftex", "parenleftbt", "bracketlefttp", "bracketleftex",
|
||||
"bracketleftbt", "bracelefttp", "braceleftmid", "braceleftbt", "braceex",
|
||||
"", "angleright", "integral", "integraltp", "integralex", "integralbt",
|
||||
"parenrighttp", "parenrightex", "parenrightbt", "bracketrighttp",
|
||||
"bracketrightex", "bracketrightbt", "bracerighttp", "bracerightmid",
|
||||
"bracerightbt", ""];
|
||||
|
||||
// prettier-ignore
|
||||
const ZapfDingbatsEncoding = [
|
||||
'', '', '', '', '', '', '', '', '', '', '', '', '', '',
|
||||
'', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
|
||||
'space', 'a1', 'a2', 'a202', 'a3', 'a4', 'a5', 'a119', 'a118', 'a117',
|
||||
'a11', 'a12', 'a13', 'a14', 'a15', 'a16', 'a105', 'a17', 'a18', 'a19',
|
||||
'a20', 'a21', 'a22', 'a23', 'a24', 'a25', 'a26', 'a27', 'a28', 'a6', 'a7',
|
||||
'a8', 'a9', 'a10', 'a29', 'a30', 'a31', 'a32', 'a33', 'a34', 'a35', 'a36',
|
||||
'a37', 'a38', 'a39', 'a40', 'a41', 'a42', 'a43', 'a44', 'a45', 'a46',
|
||||
'a47', 'a48', 'a49', 'a50', 'a51', 'a52', 'a53', 'a54', 'a55', 'a56',
|
||||
'a57', 'a58', 'a59', 'a60', 'a61', 'a62', 'a63', 'a64', 'a65', 'a66',
|
||||
'a67', 'a68', 'a69', 'a70', 'a71', 'a72', 'a73', 'a74', 'a203', 'a75',
|
||||
'a204', 'a76', 'a77', 'a78', 'a79', 'a81', 'a82', 'a83', 'a84', 'a97',
|
||||
'a98', 'a99', 'a100', '', 'a89', 'a90', 'a93', 'a94', 'a91', 'a92', 'a205',
|
||||
'a85', 'a206', 'a86', 'a87', 'a88', 'a95', 'a96', '', '', '', '', '', '',
|
||||
'', '', '', '', '', '', '', '', '', '', '', '', '', 'a101', 'a102', 'a103',
|
||||
'a104', 'a106', 'a107', 'a108', 'a112', 'a111', 'a110', 'a109', 'a120',
|
||||
'a121', 'a122', 'a123', 'a124', 'a125', 'a126', 'a127', 'a128', 'a129',
|
||||
'a130', 'a131', 'a132', 'a133', 'a134', 'a135', 'a136', 'a137', 'a138',
|
||||
'a139', 'a140', 'a141', 'a142', 'a143', 'a144', 'a145', 'a146', 'a147',
|
||||
'a148', 'a149', 'a150', 'a151', 'a152', 'a153', 'a154', 'a155', 'a156',
|
||||
'a157', 'a158', 'a159', 'a160', 'a161', 'a163', 'a164', 'a196', 'a165',
|
||||
'a192', 'a166', 'a167', 'a168', 'a169', 'a170', 'a171', 'a172', 'a173',
|
||||
'a162', 'a174', 'a175', 'a176', 'a177', 'a178', 'a179', 'a193', 'a180',
|
||||
'a199', 'a181', 'a200', 'a182', '', 'a201', 'a183', 'a184', 'a197', 'a185',
|
||||
'a194', 'a198', 'a186', 'a195', 'a187', 'a188', 'a189', 'a190', 'a191', ''];
|
||||
"", "", "", "", "", "", "", "", "", "", "", "", "", "",
|
||||
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
|
||||
"space", "a1", "a2", "a202", "a3", "a4", "a5", "a119", "a118", "a117",
|
||||
"a11", "a12", "a13", "a14", "a15", "a16", "a105", "a17", "a18", "a19",
|
||||
"a20", "a21", "a22", "a23", "a24", "a25", "a26", "a27", "a28", "a6", "a7",
|
||||
"a8", "a9", "a10", "a29", "a30", "a31", "a32", "a33", "a34", "a35", "a36",
|
||||
"a37", "a38", "a39", "a40", "a41", "a42", "a43", "a44", "a45", "a46",
|
||||
"a47", "a48", "a49", "a50", "a51", "a52", "a53", "a54", "a55", "a56",
|
||||
"a57", "a58", "a59", "a60", "a61", "a62", "a63", "a64", "a65", "a66",
|
||||
"a67", "a68", "a69", "a70", "a71", "a72", "a73", "a74", "a203", "a75",
|
||||
"a204", "a76", "a77", "a78", "a79", "a81", "a82", "a83", "a84", "a97",
|
||||
"a98", "a99", "a100", "", "a89", "a90", "a93", "a94", "a91", "a92", "a205",
|
||||
"a85", "a206", "a86", "a87", "a88", "a95", "a96", "", "", "", "", "", "",
|
||||
"", "", "", "", "", "", "", "", "", "", "", "", "", "a101", "a102", "a103",
|
||||
"a104", "a106", "a107", "a108", "a112", "a111", "a110", "a109", "a120",
|
||||
"a121", "a122", "a123", "a124", "a125", "a126", "a127", "a128", "a129",
|
||||
"a130", "a131", "a132", "a133", "a134", "a135", "a136", "a137", "a138",
|
||||
"a139", "a140", "a141", "a142", "a143", "a144", "a145", "a146", "a147",
|
||||
"a148", "a149", "a150", "a151", "a152", "a153", "a154", "a155", "a156",
|
||||
"a157", "a158", "a159", "a160", "a161", "a163", "a164", "a196", "a165",
|
||||
"a192", "a166", "a167", "a168", "a169", "a170", "a171", "a172", "a173",
|
||||
"a162", "a174", "a175", "a176", "a177", "a178", "a179", "a193", "a180",
|
||||
"a199", "a181", "a200", "a182", "", "a201", "a183", "a184", "a197", "a185",
|
||||
"a194", "a198", "a186", "a195", "a187", "a188", "a189", "a190", "a191", ""];
|
||||
|
||||
function getEncoding(encodingName) {
|
||||
switch (encodingName) {
|
||||
case 'WinAnsiEncoding':
|
||||
case "WinAnsiEncoding":
|
||||
return WinAnsiEncoding;
|
||||
case 'StandardEncoding':
|
||||
case "StandardEncoding":
|
||||
return StandardEncoding;
|
||||
case 'MacRomanEncoding':
|
||||
case "MacRomanEncoding":
|
||||
return MacRomanEncoding;
|
||||
case 'SymbolSetEncoding':
|
||||
case "SymbolSetEncoding":
|
||||
return SymbolSetEncoding;
|
||||
case 'ZapfDingbatsEncoding':
|
||||
case "ZapfDingbatsEncoding":
|
||||
return ZapfDingbatsEncoding;
|
||||
case 'ExpertEncoding':
|
||||
case "ExpertEncoding":
|
||||
return ExpertEncoding;
|
||||
case 'MacExpertEncoding':
|
||||
case "MacExpertEncoding":
|
||||
return MacExpertEncoding;
|
||||
default:
|
||||
return null;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -14,17 +14,25 @@
|
||||
*/
|
||||
|
||||
import {
|
||||
bytesToString, FONT_IDENTITY_MATRIX, FormatError, unreachable, warn
|
||||
} from '../shared/util';
|
||||
import { CFFParser } from './cff_parser';
|
||||
import { getGlyphsUnicode } from './glyphlist';
|
||||
import { StandardEncoding } from './encodings';
|
||||
import { Stream } from './stream';
|
||||
bytesToString,
|
||||
FONT_IDENTITY_MATRIX,
|
||||
FormatError,
|
||||
unreachable,
|
||||
warn,
|
||||
} from "../shared/util";
|
||||
import { CFFParser } from "./cff_parser";
|
||||
import { getGlyphsUnicode } from "./glyphlist";
|
||||
import { StandardEncoding } from "./encodings";
|
||||
import { Stream } from "./stream";
|
||||
|
||||
var FontRendererFactory = (function FontRendererFactoryClosure() {
|
||||
function getLong(data, offset) {
|
||||
return (data[offset] << 24) | (data[offset + 1] << 16) |
|
||||
(data[offset + 2] << 8) | data[offset + 3];
|
||||
return (
|
||||
(data[offset] << 24) |
|
||||
(data[offset + 1] << 16) |
|
||||
(data[offset + 2] << 8) |
|
||||
data[offset + 3]
|
||||
);
|
||||
}
|
||||
|
||||
function getUshort(data, offset) {
|
||||
@ -32,8 +40,10 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
|
||||
}
|
||||
|
||||
function parseCmap(data, start, end) {
|
||||
var offset = (getUshort(data, start + 2) === 1 ?
|
||||
getLong(data, start + 8) : getLong(data, start + 16));
|
||||
var offset =
|
||||
getUshort(data, start + 2) === 1
|
||||
? getLong(data, start + 8)
|
||||
: getLong(data, start + 16);
|
||||
var format = getUshort(data, start + offset);
|
||||
var ranges, p, i;
|
||||
if (format === 4) {
|
||||
@ -42,7 +52,7 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
|
||||
p = start + offset + 14;
|
||||
ranges = [];
|
||||
for (i = 0; i < segCount; i++, p += 2) {
|
||||
ranges[i] = { end: getUshort(data, p), };
|
||||
ranges[i] = { end: getUshort(data, p) };
|
||||
}
|
||||
p += 2;
|
||||
for (i = 0; i < segCount; i++, p += 2) {
|
||||
@ -83,13 +93,18 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
|
||||
|
||||
function parseCff(data, start, end, seacAnalysisEnabled) {
|
||||
var properties = {};
|
||||
var parser = new CFFParser(new Stream(data, start, end - start),
|
||||
properties, seacAnalysisEnabled);
|
||||
var parser = new CFFParser(
|
||||
new Stream(data, start, end - start),
|
||||
properties,
|
||||
seacAnalysisEnabled
|
||||
);
|
||||
var cff = parser.parse();
|
||||
return {
|
||||
glyphs: cff.charStrings.objects,
|
||||
subrs: (cff.topDict.privateDict && cff.topDict.privateDict.subrsIndex &&
|
||||
cff.topDict.privateDict.subrsIndex.objects),
|
||||
subrs:
|
||||
cff.topDict.privateDict &&
|
||||
cff.topDict.privateDict.subrsIndex &&
|
||||
cff.topDict.privateDict.subrsIndex.objects,
|
||||
gsubrs: cff.globalSubrIndex && cff.globalSubrIndex.objects,
|
||||
isCFFCIDFont: cff.isCIDFont,
|
||||
fdSelect: cff.fdSelect,
|
||||
@ -102,8 +117,12 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
|
||||
if (isGlyphLocationsLong) {
|
||||
itemSize = 4;
|
||||
itemDecode = function fontItemDecodeLong(data, offset) {
|
||||
return (data[offset] << 24) | (data[offset + 1] << 16) |
|
||||
(data[offset + 2] << 8) | data[offset + 3];
|
||||
return (
|
||||
(data[offset] << 24) |
|
||||
(data[offset + 1] << 16) |
|
||||
(data[offset + 2] << 8) |
|
||||
data[offset + 3]
|
||||
);
|
||||
};
|
||||
} else {
|
||||
itemSize = 2;
|
||||
@ -122,8 +141,10 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
|
||||
}
|
||||
|
||||
function lookupCmap(ranges, unicode) {
|
||||
var code = unicode.codePointAt(0), gid = 0;
|
||||
var l = 0, r = ranges.length - 1;
|
||||
var code = unicode.codePointAt(0),
|
||||
gid = 0;
|
||||
var l = 0,
|
||||
r = ranges.length - 1;
|
||||
while (l < r) {
|
||||
var c = (l + r + 1) >> 1;
|
||||
if (code < ranges[c].start) {
|
||||
@ -133,8 +154,10 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
|
||||
}
|
||||
}
|
||||
if (ranges[l].start <= code && code <= ranges[l].end) {
|
||||
gid = (ranges[l].idDelta + (ranges[l].ids ?
|
||||
ranges[l].ids[code - ranges[l].start] : code)) & 0xFFFF;
|
||||
gid =
|
||||
(ranges[l].idDelta +
|
||||
(ranges[l].ids ? ranges[l].ids[code - ranges[l].start] : code)) &
|
||||
0xffff;
|
||||
}
|
||||
return {
|
||||
charCode: code,
|
||||
@ -144,19 +167,20 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
|
||||
|
||||
function compileGlyf(code, cmds, font) {
|
||||
function moveTo(x, y) {
|
||||
cmds.push({ cmd: 'moveTo', args: [x, y], });
|
||||
cmds.push({ cmd: "moveTo", args: [x, y] });
|
||||
}
|
||||
function lineTo(x, y) {
|
||||
cmds.push({ cmd: 'lineTo', args: [x, y], });
|
||||
cmds.push({ cmd: "lineTo", args: [x, y] });
|
||||
}
|
||||
function quadraticCurveTo(xa, ya, x, y) {
|
||||
cmds.push({ cmd: 'quadraticCurveTo', args: [xa, ya, x, y], });
|
||||
cmds.push({ cmd: "quadraticCurveTo", args: [xa, ya, x, y] });
|
||||
}
|
||||
|
||||
var i = 0;
|
||||
var numberOfContours = ((code[i] << 24) | (code[i + 1] << 16)) >> 16;
|
||||
var flags;
|
||||
var x = 0, y = 0;
|
||||
var x = 0,
|
||||
y = 0;
|
||||
i += 10;
|
||||
if (numberOfContours < 0) {
|
||||
// composite glyph
|
||||
@ -165,29 +189,34 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
|
||||
var glyphIndex = (code[i + 2] << 8) | code[i + 3];
|
||||
i += 4;
|
||||
var arg1, arg2;
|
||||
if ((flags & 0x01)) {
|
||||
if (flags & 0x01) {
|
||||
arg1 = ((code[i] << 24) | (code[i + 1] << 16)) >> 16;
|
||||
arg2 = ((code[i + 2] << 24) | (code[i + 3] << 16)) >> 16;
|
||||
i += 4;
|
||||
} else {
|
||||
arg1 = code[i++]; arg2 = code[i++];
|
||||
arg1 = code[i++];
|
||||
arg2 = code[i++];
|
||||
}
|
||||
if ((flags & 0x02)) {
|
||||
x = arg1;
|
||||
y = arg2;
|
||||
if (flags & 0x02) {
|
||||
x = arg1;
|
||||
y = arg2;
|
||||
} else {
|
||||
x = 0; y = 0; // TODO "they are points" ?
|
||||
x = 0;
|
||||
y = 0; // TODO "they are points" ?
|
||||
}
|
||||
var scaleX = 1, scaleY = 1, scale01 = 0, scale10 = 0;
|
||||
if ((flags & 0x08)) {
|
||||
scaleX =
|
||||
scaleY = ((code[i] << 24) | (code[i + 1] << 16)) / 1073741824;
|
||||
var scaleX = 1,
|
||||
scaleY = 1,
|
||||
scale01 = 0,
|
||||
scale10 = 0;
|
||||
if (flags & 0x08) {
|
||||
scaleX = scaleY =
|
||||
((code[i] << 24) | (code[i + 1] << 16)) / 1073741824;
|
||||
i += 2;
|
||||
} else if ((flags & 0x40)) {
|
||||
} else if (flags & 0x40) {
|
||||
scaleX = ((code[i] << 24) | (code[i + 1] << 16)) / 1073741824;
|
||||
scaleY = ((code[i + 2] << 24) | (code[i + 3] << 16)) / 1073741824;
|
||||
i += 4;
|
||||
} else if ((flags & 0x80)) {
|
||||
} else if (flags & 0x80) {
|
||||
scaleX = ((code[i] << 24) | (code[i + 1] << 16)) / 1073741824;
|
||||
scale01 = ((code[i + 2] << 24) | (code[i + 3] << 16)) / 1073741824;
|
||||
scale10 = ((code[i + 4] << 24) | (code[i + 5] << 16)) / 1073741824;
|
||||
@ -196,13 +225,15 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
|
||||
}
|
||||
var subglyph = font.glyphs[glyphIndex];
|
||||
if (subglyph) {
|
||||
cmds.push({ cmd: 'save', });
|
||||
cmds.push({ cmd: 'transform',
|
||||
args: [scaleX, scale01, scale10, scaleY, x, y], });
|
||||
cmds.push({ cmd: "save" });
|
||||
cmds.push({
|
||||
cmd: "transform",
|
||||
args: [scaleX, scale01, scale10, scaleY, x, y],
|
||||
});
|
||||
compileGlyf(subglyph, cmds, font);
|
||||
cmds.push({ cmd: 'restore', });
|
||||
cmds.push({ cmd: "restore" });
|
||||
}
|
||||
} while ((flags & 0x20));
|
||||
} while (flags & 0x20);
|
||||
} else {
|
||||
// simple glyph
|
||||
var endPtsOfContours = [];
|
||||
@ -218,11 +249,11 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
|
||||
while (points.length < numberOfPoints) {
|
||||
flags = code[i++];
|
||||
var repeat = 1;
|
||||
if ((flags & 0x08)) {
|
||||
if (flags & 0x08) {
|
||||
repeat += code[i++];
|
||||
}
|
||||
while (repeat-- > 0) {
|
||||
points.push({ flags, });
|
||||
points.push({ flags });
|
||||
}
|
||||
}
|
||||
for (j = 0; j < numberOfPoints; j++) {
|
||||
@ -262,9 +293,9 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
|
||||
// contours might have implicit points, which is located in the middle
|
||||
// between two neighboring off-curve points
|
||||
var contour = points.slice(startPoint, endPoint + 1);
|
||||
if ((contour[0].flags & 1)) {
|
||||
if (contour[0].flags & 1) {
|
||||
contour.push(contour[0]); // using start point at the contour end
|
||||
} else if ((contour[contour.length - 1].flags & 1)) {
|
||||
} else if (contour[contour.length - 1].flags & 1) {
|
||||
// first is off-curve point, trying to use one from the end
|
||||
contour.unshift(contour[contour.length - 1]);
|
||||
} else {
|
||||
@ -279,16 +310,23 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
|
||||
}
|
||||
moveTo(contour[0].x, contour[0].y);
|
||||
for (j = 1, jj = contour.length; j < jj; j++) {
|
||||
if ((contour[j].flags & 1)) {
|
||||
if (contour[j].flags & 1) {
|
||||
lineTo(contour[j].x, contour[j].y);
|
||||
} else if ((contour[j + 1].flags & 1)) {
|
||||
quadraticCurveTo(contour[j].x, contour[j].y,
|
||||
contour[j + 1].x, contour[j + 1].y);
|
||||
} else if (contour[j + 1].flags & 1) {
|
||||
quadraticCurveTo(
|
||||
contour[j].x,
|
||||
contour[j].y,
|
||||
contour[j + 1].x,
|
||||
contour[j + 1].y
|
||||
);
|
||||
j++;
|
||||
} else {
|
||||
quadraticCurveTo(contour[j].x, contour[j].y,
|
||||
quadraticCurveTo(
|
||||
contour[j].x,
|
||||
contour[j].y,
|
||||
(contour[j].x + contour[j + 1].x) / 2,
|
||||
(contour[j].y + contour[j + 1].y) / 2);
|
||||
(contour[j].y + contour[j + 1].y) / 2
|
||||
);
|
||||
}
|
||||
}
|
||||
startPoint = endPoint + 1;
|
||||
@ -298,17 +336,18 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
|
||||
|
||||
function compileCharString(code, cmds, font, glyphId) {
|
||||
var stack = [];
|
||||
var x = 0, y = 0;
|
||||
var x = 0,
|
||||
y = 0;
|
||||
var stems = 0;
|
||||
|
||||
function moveTo(x, y) {
|
||||
cmds.push({ cmd: 'moveTo', args: [x, y], });
|
||||
cmds.push({ cmd: "moveTo", args: [x, y] });
|
||||
}
|
||||
function lineTo(x, y) {
|
||||
cmds.push({ cmd: 'lineTo', args: [x, y], });
|
||||
cmds.push({ cmd: "lineTo", args: [x, y] });
|
||||
}
|
||||
function bezierCurveTo(x1, y1, x2, y2, x, y) {
|
||||
cmds.push({ cmd: 'bezierCurveTo', args: [x1, y1, x2, y2, x, y], });
|
||||
cmds.push({ cmd: "bezierCurveTo", args: [x1, y1, x2, y2, x, y] });
|
||||
}
|
||||
|
||||
function parse(code) {
|
||||
@ -362,9 +401,12 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
|
||||
break;
|
||||
case 8: // rrcurveto
|
||||
while (stack.length > 0) {
|
||||
xa = x + stack.shift(); ya = y + stack.shift();
|
||||
xb = xa + stack.shift(); yb = ya + stack.shift();
|
||||
x = xb + stack.shift(); y = yb + stack.shift();
|
||||
xa = x + stack.shift();
|
||||
ya = y + stack.shift();
|
||||
xb = xa + stack.shift();
|
||||
yb = ya + stack.shift();
|
||||
x = xb + stack.shift();
|
||||
y = yb + stack.shift();
|
||||
bezierCurveTo(xa, ya, xb, yb, x, y);
|
||||
}
|
||||
break;
|
||||
@ -374,19 +416,19 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
|
||||
if (font.isCFFCIDFont) {
|
||||
let fdIndex = font.fdSelect.getFDIndex(glyphId);
|
||||
if (fdIndex >= 0 && fdIndex < font.fdArray.length) {
|
||||
let fontDict = font.fdArray[fdIndex], subrs;
|
||||
let fontDict = font.fdArray[fdIndex],
|
||||
subrs;
|
||||
if (fontDict.privateDict && fontDict.privateDict.subrsIndex) {
|
||||
subrs = fontDict.privateDict.subrsIndex.objects;
|
||||
}
|
||||
if (subrs) {
|
||||
let numSubrs = subrs.length;
|
||||
// Add subroutine bias.
|
||||
n += numSubrs < 1240 ? 107 :
|
||||
(numSubrs < 33900 ? 1131 : 32768);
|
||||
n += numSubrs < 1240 ? 107 : numSubrs < 33900 ? 1131 : 32768;
|
||||
subrCode = subrs[n];
|
||||
}
|
||||
} else {
|
||||
warn('Invalid fd index for glyph index.');
|
||||
warn("Invalid fd index for glyph index.");
|
||||
}
|
||||
} else {
|
||||
subrCode = font.subrs[n + font.subrsBias];
|
||||
@ -402,7 +444,8 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
|
||||
switch (v) {
|
||||
case 34: // flex
|
||||
xa = x + stack.shift();
|
||||
xb = xa + stack.shift(); y1 = y + stack.shift();
|
||||
xb = xa + stack.shift();
|
||||
y1 = y + stack.shift();
|
||||
x = xb + stack.shift();
|
||||
bezierCurveTo(xa, y, xb, y1, x, y1);
|
||||
xa = x + stack.shift();
|
||||
@ -411,35 +454,51 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
|
||||
bezierCurveTo(xa, y1, xb, y, x, y);
|
||||
break;
|
||||
case 35: // flex
|
||||
xa = x + stack.shift(); ya = y + stack.shift();
|
||||
xb = xa + stack.shift(); yb = ya + stack.shift();
|
||||
x = xb + stack.shift(); y = yb + stack.shift();
|
||||
xa = x + stack.shift();
|
||||
ya = y + stack.shift();
|
||||
xb = xa + stack.shift();
|
||||
yb = ya + stack.shift();
|
||||
x = xb + stack.shift();
|
||||
y = yb + stack.shift();
|
||||
bezierCurveTo(xa, ya, xb, yb, x, y);
|
||||
xa = x + stack.shift(); ya = y + stack.shift();
|
||||
xb = xa + stack.shift(); yb = ya + stack.shift();
|
||||
x = xb + stack.shift(); y = yb + stack.shift();
|
||||
xa = x + stack.shift();
|
||||
ya = y + stack.shift();
|
||||
xb = xa + stack.shift();
|
||||
yb = ya + stack.shift();
|
||||
x = xb + stack.shift();
|
||||
y = yb + stack.shift();
|
||||
bezierCurveTo(xa, ya, xb, yb, x, y);
|
||||
stack.pop(); // fd
|
||||
break;
|
||||
case 36: // hflex1
|
||||
xa = x + stack.shift(); y1 = y + stack.shift();
|
||||
xb = xa + stack.shift(); y2 = y1 + stack.shift();
|
||||
xa = x + stack.shift();
|
||||
y1 = y + stack.shift();
|
||||
xb = xa + stack.shift();
|
||||
y2 = y1 + stack.shift();
|
||||
x = xb + stack.shift();
|
||||
bezierCurveTo(xa, y1, xb, y2, x, y2);
|
||||
xa = x + stack.shift();
|
||||
xb = xa + stack.shift(); y3 = y2 + stack.shift();
|
||||
xb = xa + stack.shift();
|
||||
y3 = y2 + stack.shift();
|
||||
x = xb + stack.shift();
|
||||
bezierCurveTo(xa, y2, xb, y3, x, y);
|
||||
break;
|
||||
case 37: // flex1
|
||||
var x0 = x, y0 = y;
|
||||
xa = x + stack.shift(); ya = y + stack.shift();
|
||||
xb = xa + stack.shift(); yb = ya + stack.shift();
|
||||
x = xb + stack.shift(); y = yb + stack.shift();
|
||||
var x0 = x,
|
||||
y0 = y;
|
||||
xa = x + stack.shift();
|
||||
ya = y + stack.shift();
|
||||
xb = xa + stack.shift();
|
||||
yb = ya + stack.shift();
|
||||
x = xb + stack.shift();
|
||||
y = yb + stack.shift();
|
||||
bezierCurveTo(xa, ya, xb, yb, x, y);
|
||||
xa = x + stack.shift(); ya = y + stack.shift();
|
||||
xb = xa + stack.shift(); yb = ya + stack.shift();
|
||||
x = xb; y = yb;
|
||||
xa = x + stack.shift();
|
||||
ya = y + stack.shift();
|
||||
xb = xa + stack.shift();
|
||||
yb = ya + stack.shift();
|
||||
x = xb;
|
||||
y = yb;
|
||||
if (Math.abs(x - x0) > Math.abs(y - y0)) {
|
||||
x += stack.shift();
|
||||
} else {
|
||||
@ -457,18 +516,30 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
|
||||
var bchar = stack.pop();
|
||||
y = stack.pop();
|
||||
x = stack.pop();
|
||||
cmds.push({ cmd: 'save', });
|
||||
cmds.push({ cmd: 'translate', args: [x, y], });
|
||||
var cmap = lookupCmap(font.cmap, String.fromCharCode(
|
||||
font.glyphNameMap[StandardEncoding[achar]]));
|
||||
compileCharString(font.glyphs[cmap.glyphId], cmds, font,
|
||||
cmap.glyphId);
|
||||
cmds.push({ cmd: 'restore', });
|
||||
cmds.push({ cmd: "save" });
|
||||
cmds.push({ cmd: "translate", args: [x, y] });
|
||||
var cmap = lookupCmap(
|
||||
font.cmap,
|
||||
String.fromCharCode(font.glyphNameMap[StandardEncoding[achar]])
|
||||
);
|
||||
compileCharString(
|
||||
font.glyphs[cmap.glyphId],
|
||||
cmds,
|
||||
font,
|
||||
cmap.glyphId
|
||||
);
|
||||
cmds.push({ cmd: "restore" });
|
||||
|
||||
cmap = lookupCmap(font.cmap, String.fromCharCode(
|
||||
font.glyphNameMap[StandardEncoding[bchar]]));
|
||||
compileCharString(font.glyphs[cmap.glyphId], cmds, font,
|
||||
cmap.glyphId);
|
||||
cmap = lookupCmap(
|
||||
font.cmap,
|
||||
String.fromCharCode(font.glyphNameMap[StandardEncoding[bchar]])
|
||||
);
|
||||
compileCharString(
|
||||
font.glyphs[cmap.glyphId],
|
||||
cmds,
|
||||
font,
|
||||
cmap.glyphId
|
||||
);
|
||||
}
|
||||
return;
|
||||
case 18: // hstemhm
|
||||
@ -502,9 +573,12 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
|
||||
break;
|
||||
case 24: // rcurveline
|
||||
while (stack.length > 2) {
|
||||
xa = x + stack.shift(); ya = y + stack.shift();
|
||||
xb = xa + stack.shift(); yb = ya + stack.shift();
|
||||
x = xb + stack.shift(); y = yb + stack.shift();
|
||||
xa = x + stack.shift();
|
||||
ya = y + stack.shift();
|
||||
xb = xa + stack.shift();
|
||||
yb = ya + stack.shift();
|
||||
x = xb + stack.shift();
|
||||
y = yb + stack.shift();
|
||||
bezierCurveTo(xa, ya, xb, yb, x, y);
|
||||
}
|
||||
x += stack.shift();
|
||||
@ -517,9 +591,12 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
|
||||
y += stack.shift();
|
||||
lineTo(x, y);
|
||||
}
|
||||
xa = x + stack.shift(); ya = y + stack.shift();
|
||||
xb = xa + stack.shift(); yb = ya + stack.shift();
|
||||
x = xb + stack.shift(); y = yb + stack.shift();
|
||||
xa = x + stack.shift();
|
||||
ya = y + stack.shift();
|
||||
xb = xa + stack.shift();
|
||||
yb = ya + stack.shift();
|
||||
x = xb + stack.shift();
|
||||
y = yb + stack.shift();
|
||||
bezierCurveTo(xa, ya, xb, yb, x, y);
|
||||
break;
|
||||
case 26: // vvcurveto
|
||||
@ -527,9 +604,12 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
|
||||
x += stack.shift();
|
||||
}
|
||||
while (stack.length > 0) {
|
||||
xa = x; ya = y + stack.shift();
|
||||
xb = xa + stack.shift(); yb = ya + stack.shift();
|
||||
x = xb; y = yb + stack.shift();
|
||||
xa = x;
|
||||
ya = y + stack.shift();
|
||||
xb = xa + stack.shift();
|
||||
yb = ya + stack.shift();
|
||||
x = xb;
|
||||
y = yb + stack.shift();
|
||||
bezierCurveTo(xa, ya, xb, yb, x, y);
|
||||
}
|
||||
break;
|
||||
@ -538,9 +618,12 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
|
||||
y += stack.shift();
|
||||
}
|
||||
while (stack.length > 0) {
|
||||
xa = x + stack.shift(); ya = y;
|
||||
xb = xa + stack.shift(); yb = ya + stack.shift();
|
||||
x = xb + stack.shift(); y = yb;
|
||||
xa = x + stack.shift();
|
||||
ya = y;
|
||||
xb = xa + stack.shift();
|
||||
yb = ya + stack.shift();
|
||||
x = xb + stack.shift();
|
||||
y = yb;
|
||||
bezierCurveTo(xa, ya, xb, yb, x, y);
|
||||
}
|
||||
break;
|
||||
@ -557,8 +640,10 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
|
||||
break;
|
||||
case 30: // vhcurveto
|
||||
while (stack.length > 0) {
|
||||
xa = x; ya = y + stack.shift();
|
||||
xb = xa + stack.shift(); yb = ya + stack.shift();
|
||||
xa = x;
|
||||
ya = y + stack.shift();
|
||||
xb = xa + stack.shift();
|
||||
yb = ya + stack.shift();
|
||||
x = xb + stack.shift();
|
||||
y = yb + (stack.length === 1 ? stack.shift() : 0);
|
||||
bezierCurveTo(xa, ya, xb, yb, x, y);
|
||||
@ -566,8 +651,10 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
|
||||
break;
|
||||
}
|
||||
|
||||
xa = x + stack.shift(); ya = y;
|
||||
xb = xa + stack.shift(); yb = ya + stack.shift();
|
||||
xa = x + stack.shift();
|
||||
ya = y;
|
||||
xb = xa + stack.shift();
|
||||
yb = ya + stack.shift();
|
||||
y = yb + stack.shift();
|
||||
x = xb + (stack.length === 1 ? stack.shift() : 0);
|
||||
bezierCurveTo(xa, ya, xb, yb, x, y);
|
||||
@ -575,8 +662,10 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
|
||||
break;
|
||||
case 31: // hvcurveto
|
||||
while (stack.length > 0) {
|
||||
xa = x + stack.shift(); ya = y;
|
||||
xb = xa + stack.shift(); yb = ya + stack.shift();
|
||||
xa = x + stack.shift();
|
||||
ya = y;
|
||||
xb = xa + stack.shift();
|
||||
yb = ya + stack.shift();
|
||||
y = yb + stack.shift();
|
||||
x = xb + (stack.length === 1 ? stack.shift() : 0);
|
||||
bezierCurveTo(xa, ya, xb, yb, x, y);
|
||||
@ -584,8 +673,10 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
|
||||
break;
|
||||
}
|
||||
|
||||
xa = x; ya = y + stack.shift();
|
||||
xb = xa + stack.shift(); yb = ya + stack.shift();
|
||||
xa = x;
|
||||
ya = y + stack.shift();
|
||||
xb = xa + stack.shift();
|
||||
yb = ya + stack.shift();
|
||||
x = xb + stack.shift();
|
||||
y = yb + (stack.length === 1 ? stack.shift() : 0);
|
||||
bezierCurveTo(xa, ya, xb, yb, x, y);
|
||||
@ -602,8 +693,13 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
|
||||
} else if (v < 255) {
|
||||
stack.push(-(v - 251) * 256 - code[i++] - 108);
|
||||
} else {
|
||||
stack.push(((code[i] << 24) | (code[i + 1] << 16) |
|
||||
(code[i + 2] << 8) | code[i + 3]) / 65536);
|
||||
stack.push(
|
||||
((code[i] << 24) |
|
||||
(code[i + 1] << 16) |
|
||||
(code[i + 2] << 8) |
|
||||
code[i + 3]) /
|
||||
65536
|
||||
);
|
||||
i += 4;
|
||||
}
|
||||
break;
|
||||
@ -621,7 +717,7 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
|
||||
class CompiledFont {
|
||||
constructor(fontMatrix) {
|
||||
if (this.constructor === CompiledFont) {
|
||||
unreachable('Cannot initialize CompiledFont.');
|
||||
unreachable("Cannot initialize CompiledFont.");
|
||||
}
|
||||
this.fontMatrix = fontMatrix;
|
||||
|
||||
@ -654,32 +750,34 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
|
||||
let fdIndex = this.fdSelect.getFDIndex(glyphId);
|
||||
if (fdIndex >= 0 && fdIndex < this.fdArray.length) {
|
||||
let fontDict = this.fdArray[fdIndex];
|
||||
fontMatrix = fontDict.getByName('FontMatrix') || FONT_IDENTITY_MATRIX;
|
||||
fontMatrix = fontDict.getByName("FontMatrix") || FONT_IDENTITY_MATRIX;
|
||||
} else {
|
||||
warn('Invalid fd index for glyph index.');
|
||||
warn("Invalid fd index for glyph index.");
|
||||
}
|
||||
}
|
||||
|
||||
const cmds = [];
|
||||
cmds.push({ cmd: 'save', });
|
||||
cmds.push({ cmd: 'transform', args: fontMatrix.slice(), });
|
||||
cmds.push({ cmd: 'scale', args: ['size', '-size'], });
|
||||
cmds.push({ cmd: "save" });
|
||||
cmds.push({ cmd: "transform", args: fontMatrix.slice() });
|
||||
cmds.push({ cmd: "scale", args: ["size", "-size"] });
|
||||
|
||||
this.compileGlyphImpl(code, cmds, glyphId);
|
||||
|
||||
cmds.push({ cmd: 'restore', });
|
||||
cmds.push({ cmd: "restore" });
|
||||
|
||||
return cmds;
|
||||
}
|
||||
|
||||
compileGlyphImpl() {
|
||||
unreachable('Children classes should implement this.');
|
||||
unreachable("Children classes should implement this.");
|
||||
}
|
||||
|
||||
hasBuiltPath(unicode) {
|
||||
const cmap = lookupCmap(this.cmap, unicode);
|
||||
return (this.compiledGlyphs[cmap.glyphId] !== undefined &&
|
||||
this.compiledCharCodeToGlyphId[cmap.charCode] !== undefined);
|
||||
return (
|
||||
this.compiledGlyphs[cmap.glyphId] !== undefined &&
|
||||
this.compiledCharCodeToGlyphId[cmap.charCode] !== undefined
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -706,10 +804,18 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
|
||||
this.cmap = cmap;
|
||||
this.glyphNameMap = glyphNameMap || getGlyphsUnicode();
|
||||
|
||||
this.gsubrsBias = (this.gsubrs.length < 1240 ?
|
||||
107 : (this.gsubrs.length < 33900 ? 1131 : 32768));
|
||||
this.subrsBias = (this.subrs.length < 1240 ?
|
||||
107 : (this.subrs.length < 33900 ? 1131 : 32768));
|
||||
this.gsubrsBias =
|
||||
this.gsubrs.length < 1240
|
||||
? 107
|
||||
: this.gsubrs.length < 33900
|
||||
? 1131
|
||||
: 32768;
|
||||
this.subrsBias =
|
||||
this.subrs.length < 1240
|
||||
? 107
|
||||
: this.subrs.length < 33900
|
||||
? 1131
|
||||
: 32768;
|
||||
|
||||
this.isCFFCIDFont = cffInfo.isCFFCIDFont;
|
||||
this.fdSelect = cffInfo.fdSelect;
|
||||
@ -731,36 +837,38 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
|
||||
var offset = getLong(data, p + 8);
|
||||
var length = getLong(data, p + 12);
|
||||
switch (tag) {
|
||||
case 'cmap':
|
||||
case "cmap":
|
||||
cmap = parseCmap(data, offset, offset + length);
|
||||
break;
|
||||
case 'glyf':
|
||||
case "glyf":
|
||||
glyf = data.subarray(offset, offset + length);
|
||||
break;
|
||||
case 'loca':
|
||||
case "loca":
|
||||
loca = data.subarray(offset, offset + length);
|
||||
break;
|
||||
case 'head':
|
||||
case "head":
|
||||
unitsPerEm = getUshort(data, offset + 18);
|
||||
indexToLocFormat = getUshort(data, offset + 50);
|
||||
break;
|
||||
case 'CFF ':
|
||||
case "CFF ":
|
||||
cff = parseCff(data, offset, offset + length, seacAnalysisEnabled);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (glyf) {
|
||||
var fontMatrix = (!unitsPerEm ? font.fontMatrix :
|
||||
[1 / unitsPerEm, 0, 0, 1 / unitsPerEm, 0, 0]);
|
||||
var fontMatrix = !unitsPerEm
|
||||
? font.fontMatrix
|
||||
: [1 / unitsPerEm, 0, 0, 1 / unitsPerEm, 0, 0];
|
||||
return new TrueTypeCompiled(
|
||||
parseGlyfTable(glyf, loca, indexToLocFormat), cmap, fontMatrix);
|
||||
parseGlyfTable(glyf, loca, indexToLocFormat),
|
||||
cmap,
|
||||
fontMatrix
|
||||
);
|
||||
}
|
||||
return new Type2Compiled(cff, cmap, font.fontMatrix, font.glyphNameMap);
|
||||
},
|
||||
};
|
||||
})();
|
||||
|
||||
export {
|
||||
FontRendererFactory,
|
||||
};
|
||||
export { FontRendererFactory };
|
||||
|
1896
src/core/fonts.js
1896
src/core/fonts.js
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -13,12 +13,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { assert, FormatError, ImageKind, info, warn } from '../shared/util';
|
||||
import { isName, isStream, Name } from './primitives';
|
||||
import { ColorSpace } from './colorspace';
|
||||
import { DecodeStream } from './stream';
|
||||
import { JpegStream } from './jpeg_stream';
|
||||
import { JpxImage } from './jpx';
|
||||
import { assert, FormatError, ImageKind, info, warn } from "../shared/util";
|
||||
import { isName, isStream, Name } from "./primitives";
|
||||
import { ColorSpace } from "./colorspace";
|
||||
import { DecodeStream } from "./stream";
|
||||
import { JpegStream } from "./jpeg_stream";
|
||||
import { JpxImage } from "./jpx";
|
||||
|
||||
var PDFImage = (function PDFImageClosure() {
|
||||
/**
|
||||
@ -27,9 +27,11 @@ var PDFImage = (function PDFImageClosure() {
|
||||
*/
|
||||
function handleImageData(image, nativeDecoder) {
|
||||
if (nativeDecoder && nativeDecoder.canDecode(image)) {
|
||||
return nativeDecoder.decode(image).catch((reason) => {
|
||||
warn('Native image decoding failed -- trying to recover: ' +
|
||||
(reason && reason.message));
|
||||
return nativeDecoder.decode(image).catch(reason => {
|
||||
warn(
|
||||
"Native image decoding failed -- trying to recover: " +
|
||||
(reason && reason.message)
|
||||
);
|
||||
return image;
|
||||
});
|
||||
}
|
||||
@ -43,7 +45,7 @@ var PDFImage = (function PDFImageClosure() {
|
||||
function decodeAndClamp(value, addend, coefficient, max) {
|
||||
value = addend + value * coefficient;
|
||||
// Clamp the value to the range
|
||||
return (value < 0 ? 0 : (value > max ? max : value));
|
||||
return value < 0 ? 0 : value > max ? max : value;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -58,11 +60,19 @@ var PDFImage = (function PDFImageClosure() {
|
||||
*/
|
||||
function resizeImageMask(src, bpc, w1, h1, w2, h2) {
|
||||
var length = w2 * h2;
|
||||
var dest = (bpc <= 8 ? new Uint8Array(length) :
|
||||
(bpc <= 16 ? new Uint16Array(length) : new Uint32Array(length)));
|
||||
var dest =
|
||||
bpc <= 8
|
||||
? new Uint8Array(length)
|
||||
: bpc <= 16
|
||||
? new Uint16Array(length)
|
||||
: new Uint32Array(length);
|
||||
var xRatio = w1 / w2;
|
||||
var yRatio = h1 / h2;
|
||||
var i, j, py, newIndex = 0, oldIndex;
|
||||
var i,
|
||||
j,
|
||||
py,
|
||||
newIndex = 0,
|
||||
oldIndex;
|
||||
var xScaled = new Uint16Array(w2);
|
||||
var w1Scanline = w1;
|
||||
|
||||
@ -79,15 +89,23 @@ var PDFImage = (function PDFImageClosure() {
|
||||
return dest;
|
||||
}
|
||||
|
||||
function PDFImage({ xref, res, image, isInline = false, smask = null,
|
||||
mask = null, isMask = false, pdfFunctionFactory, }) {
|
||||
function PDFImage({
|
||||
xref,
|
||||
res,
|
||||
image,
|
||||
isInline = false,
|
||||
smask = null,
|
||||
mask = null,
|
||||
isMask = false,
|
||||
pdfFunctionFactory,
|
||||
}) {
|
||||
this.image = image;
|
||||
var dict = image.dict;
|
||||
|
||||
const filter = dict.get('Filter');
|
||||
const filter = dict.get("Filter");
|
||||
if (isName(filter)) {
|
||||
switch (filter.name) {
|
||||
case 'JPXDecode':
|
||||
case "JPXDecode":
|
||||
var jpxImage = new JpxImage();
|
||||
jpxImage.parseImageProperties(image.stream);
|
||||
image.stream.reset();
|
||||
@ -97,7 +115,7 @@ var PDFImage = (function PDFImageClosure() {
|
||||
image.bitsPerComponent = jpxImage.bitsPerComponent;
|
||||
image.numComps = jpxImage.componentsCount;
|
||||
break;
|
||||
case 'JBIG2Decode':
|
||||
case "JBIG2Decode":
|
||||
image.bitsPerComponent = 1;
|
||||
image.numComps = 1;
|
||||
break;
|
||||
@ -105,86 +123,103 @@ var PDFImage = (function PDFImageClosure() {
|
||||
}
|
||||
// TODO cache rendered images?
|
||||
|
||||
let width = dict.get('Width', 'W');
|
||||
let height = dict.get('Height', 'H');
|
||||
let width = dict.get("Width", "W");
|
||||
let height = dict.get("Height", "H");
|
||||
|
||||
if ((Number.isInteger(image.width) && image.width > 0) &&
|
||||
(Number.isInteger(image.height) && image.height > 0) &&
|
||||
(image.width !== width || image.height !== height)) {
|
||||
warn('PDFImage - using the Width/Height of the image data, ' +
|
||||
'rather than the image dictionary.');
|
||||
if (
|
||||
Number.isInteger(image.width) &&
|
||||
image.width > 0 &&
|
||||
Number.isInteger(image.height) &&
|
||||
image.height > 0 &&
|
||||
(image.width !== width || image.height !== height)
|
||||
) {
|
||||
warn(
|
||||
"PDFImage - using the Width/Height of the image data, " +
|
||||
"rather than the image dictionary."
|
||||
);
|
||||
width = image.width;
|
||||
height = image.height;
|
||||
}
|
||||
if (width < 1 || height < 1) {
|
||||
throw new FormatError(`Invalid image width: ${width} or ` +
|
||||
`height: ${height}`);
|
||||
throw new FormatError(
|
||||
`Invalid image width: ${width} or height: ${height}`
|
||||
);
|
||||
}
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
|
||||
this.interpolate = dict.get('Interpolate', 'I') || false;
|
||||
this.imageMask = dict.get('ImageMask', 'IM') || false;
|
||||
this.matte = dict.get('Matte') || false;
|
||||
this.interpolate = dict.get("Interpolate", "I") || false;
|
||||
this.imageMask = dict.get("ImageMask", "IM") || false;
|
||||
this.matte = dict.get("Matte") || false;
|
||||
|
||||
var bitsPerComponent = image.bitsPerComponent;
|
||||
if (!bitsPerComponent) {
|
||||
bitsPerComponent = dict.get('BitsPerComponent', 'BPC');
|
||||
bitsPerComponent = dict.get("BitsPerComponent", "BPC");
|
||||
if (!bitsPerComponent) {
|
||||
if (this.imageMask) {
|
||||
bitsPerComponent = 1;
|
||||
} else {
|
||||
throw new FormatError(
|
||||
`Bits per component missing in image: ${this.imageMask}`);
|
||||
`Bits per component missing in image: ${this.imageMask}`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.bpc = bitsPerComponent;
|
||||
|
||||
if (!this.imageMask) {
|
||||
var colorSpace = dict.get('ColorSpace', 'CS');
|
||||
var colorSpace = dict.get("ColorSpace", "CS");
|
||||
if (!colorSpace) {
|
||||
info('JPX images (which do not require color spaces)');
|
||||
info("JPX images (which do not require color spaces)");
|
||||
switch (image.numComps) {
|
||||
case 1:
|
||||
colorSpace = Name.get('DeviceGray');
|
||||
colorSpace = Name.get("DeviceGray");
|
||||
break;
|
||||
case 3:
|
||||
colorSpace = Name.get('DeviceRGB');
|
||||
colorSpace = Name.get("DeviceRGB");
|
||||
break;
|
||||
case 4:
|
||||
colorSpace = Name.get('DeviceCMYK');
|
||||
colorSpace = Name.get("DeviceCMYK");
|
||||
break;
|
||||
default:
|
||||
throw new Error(`JPX images with ${image.numComps} ` +
|
||||
'color components not supported.');
|
||||
throw new Error(
|
||||
`JPX images with ${image.numComps} ` +
|
||||
"color components not supported."
|
||||
);
|
||||
}
|
||||
}
|
||||
let resources = isInline ? res : null;
|
||||
this.colorSpace = ColorSpace.parse(colorSpace, xref, resources,
|
||||
pdfFunctionFactory);
|
||||
this.colorSpace = ColorSpace.parse(
|
||||
colorSpace,
|
||||
xref,
|
||||
resources,
|
||||
pdfFunctionFactory
|
||||
);
|
||||
this.numComps = this.colorSpace.numComps;
|
||||
}
|
||||
|
||||
this.decode = dict.getArray('Decode', 'D');
|
||||
this.decode = dict.getArray("Decode", "D");
|
||||
this.needsDecode = false;
|
||||
if (this.decode &&
|
||||
((this.colorSpace &&
|
||||
!this.colorSpace.isDefaultDecode(this.decode, bitsPerComponent)) ||
|
||||
(isMask &&
|
||||
!ColorSpace.isDefaultDecode(this.decode, /* numComps = */ 1)))) {
|
||||
if (
|
||||
this.decode &&
|
||||
((this.colorSpace &&
|
||||
!this.colorSpace.isDefaultDecode(this.decode, bitsPerComponent)) ||
|
||||
(isMask &&
|
||||
!ColorSpace.isDefaultDecode(this.decode, /* numComps = */ 1)))
|
||||
) {
|
||||
this.needsDecode = true;
|
||||
// Do some preprocessing to avoid more math.
|
||||
var max = (1 << bitsPerComponent) - 1;
|
||||
this.decodeCoefficients = [];
|
||||
this.decodeAddends = [];
|
||||
const isIndexed = this.colorSpace && this.colorSpace.name === 'Indexed';
|
||||
const isIndexed = this.colorSpace && this.colorSpace.name === "Indexed";
|
||||
for (var i = 0, j = 0; i < this.decode.length; i += 2, ++j) {
|
||||
var dmin = this.decode[i];
|
||||
var dmax = this.decode[i + 1];
|
||||
this.decodeCoefficients[j] = isIndexed ? ((dmax - dmin) / max) :
|
||||
(dmax - dmin);
|
||||
this.decodeAddends[j] = isIndexed ? dmin : (max * dmin);
|
||||
this.decodeCoefficients[j] = isIndexed
|
||||
? (dmax - dmin) / max
|
||||
: dmax - dmin;
|
||||
this.decodeAddends[j] = isIndexed ? dmin : max * dmin;
|
||||
}
|
||||
}
|
||||
|
||||
@ -198,9 +233,10 @@ var PDFImage = (function PDFImageClosure() {
|
||||
});
|
||||
} else if (mask) {
|
||||
if (isStream(mask)) {
|
||||
var maskDict = mask.dict, imageMask = maskDict.get('ImageMask', 'IM');
|
||||
var maskDict = mask.dict,
|
||||
imageMask = maskDict.get("ImageMask", "IM");
|
||||
if (!imageMask) {
|
||||
warn('Ignoring /Mask in image without /ImageMask.');
|
||||
warn("Ignoring /Mask in image without /ImageMask.");
|
||||
} else {
|
||||
this.mask = new PDFImage({
|
||||
xref,
|
||||
@ -221,15 +257,21 @@ var PDFImage = (function PDFImageClosure() {
|
||||
* Handles processing of image data and returns the Promise that is resolved
|
||||
* with a PDFImage when the image is ready to be used.
|
||||
*/
|
||||
PDFImage.buildImage = function({ handler, xref, res, image, isInline = false,
|
||||
nativeDecoder = null,
|
||||
pdfFunctionFactory, }) {
|
||||
PDFImage.buildImage = function({
|
||||
handler,
|
||||
xref,
|
||||
res,
|
||||
image,
|
||||
isInline = false,
|
||||
nativeDecoder = null,
|
||||
pdfFunctionFactory,
|
||||
}) {
|
||||
var imagePromise = handleImageData(image, nativeDecoder);
|
||||
var smaskPromise;
|
||||
var maskPromise;
|
||||
|
||||
var smask = image.dict.get('SMask');
|
||||
var mask = image.dict.get('Mask');
|
||||
var smask = image.dict.get("SMask");
|
||||
var mask = image.dict.get("Mask");
|
||||
|
||||
if (smask) {
|
||||
smaskPromise = handleImageData(smask, nativeDecoder);
|
||||
@ -242,7 +284,7 @@ var PDFImage = (function PDFImageClosure() {
|
||||
} else if (Array.isArray(mask)) {
|
||||
maskPromise = Promise.resolve(mask);
|
||||
} else {
|
||||
warn('Unsupported mask format.');
|
||||
warn("Unsupported mask format.");
|
||||
maskPromise = Promise.resolve(null);
|
||||
}
|
||||
} else {
|
||||
@ -260,15 +302,25 @@ var PDFImage = (function PDFImageClosure() {
|
||||
mask: maskData,
|
||||
pdfFunctionFactory,
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
PDFImage.createMask = function({ imgArray, width, height,
|
||||
imageIsFromDecodeStream, inverseDecode, }) {
|
||||
if (typeof PDFJSDev === 'undefined' ||
|
||||
PDFJSDev.test('!PRODUCTION || TESTING')) {
|
||||
assert(imgArray instanceof Uint8ClampedArray,
|
||||
'PDFImage.createMask: Unsupported "imgArray" type.');
|
||||
PDFImage.createMask = function({
|
||||
imgArray,
|
||||
width,
|
||||
height,
|
||||
imageIsFromDecodeStream,
|
||||
inverseDecode,
|
||||
}) {
|
||||
if (
|
||||
typeof PDFJSDev === "undefined" ||
|
||||
PDFJSDev.test("!PRODUCTION || TESTING")
|
||||
) {
|
||||
assert(
|
||||
imgArray instanceof Uint8ClampedArray,
|
||||
'PDFImage.createMask: Unsupported "imgArray" type.'
|
||||
);
|
||||
}
|
||||
// |imgArray| might not contain full data for every pixel of the mask, so
|
||||
// we need to distinguish between |computedLength| and |actualLength|.
|
||||
@ -301,24 +353,28 @@ var PDFImage = (function PDFImageClosure() {
|
||||
// in this thread can be relying on its contents.
|
||||
if (inverseDecode) {
|
||||
for (i = 0; i < actualLength; i++) {
|
||||
data[i] ^= 0xFF;
|
||||
data[i] ^= 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
return { data, width, height, };
|
||||
return { data, width, height };
|
||||
};
|
||||
|
||||
PDFImage.prototype = {
|
||||
get drawWidth() {
|
||||
return Math.max(this.width,
|
||||
this.smask && this.smask.width || 0,
|
||||
this.mask && this.mask.width || 0);
|
||||
return Math.max(
|
||||
this.width,
|
||||
(this.smask && this.smask.width) || 0,
|
||||
(this.mask && this.mask.width) || 0
|
||||
);
|
||||
},
|
||||
|
||||
get drawHeight() {
|
||||
return Math.max(this.height,
|
||||
this.smask && this.smask.height || 0,
|
||||
this.mask && this.mask.height || 0);
|
||||
return Math.max(
|
||||
this.height,
|
||||
(this.smask && this.smask.height) || 0,
|
||||
(this.mask && this.mask.height) || 0
|
||||
);
|
||||
},
|
||||
|
||||
decodeBuffer(buffer) {
|
||||
@ -333,15 +389,19 @@ var PDFImage = (function PDFImageClosure() {
|
||||
if (bpc === 1) {
|
||||
// If the buffer needed decode that means it just needs to be inverted.
|
||||
for (i = 0, ii = buffer.length; i < ii; i++) {
|
||||
buffer[i] = +!(buffer[i]);
|
||||
buffer[i] = +!buffer[i];
|
||||
}
|
||||
return;
|
||||
}
|
||||
var index = 0;
|
||||
for (i = 0, ii = this.width * this.height; i < ii; i++) {
|
||||
for (var j = 0; j < numComps; j++) {
|
||||
buffer[index] = decodeAndClamp(buffer[index], decodeAddends[j],
|
||||
decodeCoefficients[j], max);
|
||||
buffer[index] = decodeAndClamp(
|
||||
buffer[index],
|
||||
decodeAddends[j],
|
||||
decodeCoefficients[j],
|
||||
max
|
||||
);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
@ -361,12 +421,18 @@ var PDFImage = (function PDFImageClosure() {
|
||||
|
||||
var length = width * height * numComps;
|
||||
var bufferPos = 0;
|
||||
var output = (bpc <= 8 ? new Uint8Array(length) :
|
||||
(bpc <= 16 ? new Uint16Array(length) : new Uint32Array(length)));
|
||||
var output =
|
||||
bpc <= 8
|
||||
? new Uint8Array(length)
|
||||
: bpc <= 16
|
||||
? new Uint16Array(length)
|
||||
: new Uint32Array(length);
|
||||
var rowComps = width * numComps;
|
||||
|
||||
var max = (1 << bpc) - 1;
|
||||
var i = 0, ii, buf;
|
||||
var i = 0,
|
||||
ii,
|
||||
buf;
|
||||
|
||||
if (bpc === 1) {
|
||||
// Optimization for reading 1 bpc images.
|
||||
@ -416,7 +482,7 @@ var PDFImage = (function PDFImageClosure() {
|
||||
|
||||
var remainingBits = bits - bpc;
|
||||
var value = buf >> remainingBits;
|
||||
output[i] = (value < 0 ? 0 : (value > max ? max : value));
|
||||
output[i] = value < 0 ? 0 : value > max ? max : value;
|
||||
buf = buf & ((1 << remainingBits) - 1);
|
||||
bits = remainingBits;
|
||||
}
|
||||
@ -425,10 +491,14 @@ var PDFImage = (function PDFImageClosure() {
|
||||
},
|
||||
|
||||
fillOpacity(rgbaBuf, width, height, actualHeight, image) {
|
||||
if (typeof PDFJSDev === 'undefined' ||
|
||||
PDFJSDev.test('!PRODUCTION || TESTING')) {
|
||||
assert(rgbaBuf instanceof Uint8ClampedArray,
|
||||
'PDFImage.fillOpacity: Unsupported "rgbaBuf" type.');
|
||||
if (
|
||||
typeof PDFJSDev === "undefined" ||
|
||||
PDFJSDev.test("!PRODUCTION || TESTING")
|
||||
) {
|
||||
assert(
|
||||
rgbaBuf instanceof Uint8ClampedArray,
|
||||
'PDFImage.fillOpacity: Unsupported "rgbaBuf" type.'
|
||||
);
|
||||
}
|
||||
var smask = this.smask;
|
||||
var mask = this.mask;
|
||||
@ -440,8 +510,14 @@ var PDFImage = (function PDFImageClosure() {
|
||||
alphaBuf = new Uint8ClampedArray(sw * sh);
|
||||
smask.fillGrayBuffer(alphaBuf);
|
||||
if (sw !== width || sh !== height) {
|
||||
alphaBuf = resizeImageMask(alphaBuf, smask.bpc, sw, sh,
|
||||
width, height);
|
||||
alphaBuf = resizeImageMask(
|
||||
alphaBuf,
|
||||
smask.bpc,
|
||||
sw,
|
||||
sh,
|
||||
width,
|
||||
height
|
||||
);
|
||||
}
|
||||
} else if (mask) {
|
||||
if (mask instanceof PDFImage) {
|
||||
@ -457,8 +533,14 @@ var PDFImage = (function PDFImageClosure() {
|
||||
}
|
||||
|
||||
if (sw !== width || sh !== height) {
|
||||
alphaBuf = resizeImageMask(alphaBuf, mask.bpc, sw, sh,
|
||||
width, height);
|
||||
alphaBuf = resizeImageMask(
|
||||
alphaBuf,
|
||||
mask.bpc,
|
||||
sw,
|
||||
sh,
|
||||
width,
|
||||
height
|
||||
);
|
||||
}
|
||||
} else if (Array.isArray(mask)) {
|
||||
// Color key mask: if any of the components are outside the range
|
||||
@ -479,7 +561,7 @@ var PDFImage = (function PDFImageClosure() {
|
||||
alphaBuf[i] = opacity;
|
||||
}
|
||||
} else {
|
||||
throw new FormatError('Unknown mask format.');
|
||||
throw new FormatError("Unknown mask format.");
|
||||
}
|
||||
}
|
||||
|
||||
@ -496,10 +578,14 @@ var PDFImage = (function PDFImageClosure() {
|
||||
},
|
||||
|
||||
undoPreblend(buffer, width, height) {
|
||||
if (typeof PDFJSDev === 'undefined' ||
|
||||
PDFJSDev.test('!PRODUCTION || TESTING')) {
|
||||
assert(buffer instanceof Uint8ClampedArray,
|
||||
'PDFImage.undoPreblend: Unsupported "buffer" type.');
|
||||
if (
|
||||
typeof PDFJSDev === "undefined" ||
|
||||
PDFJSDev.test("!PRODUCTION || TESTING")
|
||||
) {
|
||||
assert(
|
||||
buffer instanceof Uint8ClampedArray,
|
||||
'PDFImage.undoPreblend: Unsupported "buffer" type.'
|
||||
);
|
||||
}
|
||||
var matte = this.smask && this.smask.matte;
|
||||
if (!matte) {
|
||||
@ -530,11 +616,12 @@ var PDFImage = (function PDFImageClosure() {
|
||||
createImageData(forceRGBA = false) {
|
||||
var drawWidth = this.drawWidth;
|
||||
var drawHeight = this.drawHeight;
|
||||
var imgData = { // other fields are filled in below
|
||||
var imgData = {
|
||||
width: drawWidth,
|
||||
height: drawHeight,
|
||||
kind: 0,
|
||||
data: null,
|
||||
// Other fields are filled in below.
|
||||
};
|
||||
|
||||
var numComps = this.numComps;
|
||||
@ -555,14 +642,22 @@ var PDFImage = (function PDFImageClosure() {
|
||||
// Similarly, if it is a 24-bit-per pixel RGB image without any
|
||||
// complications, we avoid expanding by 1.333x to RGBA form.
|
||||
var kind;
|
||||
if (this.colorSpace.name === 'DeviceGray' && bpc === 1) {
|
||||
if (this.colorSpace.name === "DeviceGray" && bpc === 1) {
|
||||
kind = ImageKind.GRAYSCALE_1BPP;
|
||||
} else if (this.colorSpace.name === 'DeviceRGB' && bpc === 8 &&
|
||||
!this.needsDecode) {
|
||||
} else if (
|
||||
this.colorSpace.name === "DeviceRGB" &&
|
||||
bpc === 8 &&
|
||||
!this.needsDecode
|
||||
) {
|
||||
kind = ImageKind.RGB_24BPP;
|
||||
}
|
||||
if (kind && !this.smask && !this.mask &&
|
||||
drawWidth === originalWidth && drawHeight === originalHeight) {
|
||||
if (
|
||||
kind &&
|
||||
!this.smask &&
|
||||
!this.mask &&
|
||||
drawWidth === originalWidth &&
|
||||
drawHeight === originalHeight
|
||||
) {
|
||||
imgData.kind = kind;
|
||||
|
||||
imgArray = this.getImageBytes(originalHeight * rowBytes);
|
||||
@ -580,8 +675,10 @@ var PDFImage = (function PDFImageClosure() {
|
||||
}
|
||||
if (this.needsDecode) {
|
||||
// Invert the buffer (which must be grayscale if we reached here).
|
||||
assert(kind === ImageKind.GRAYSCALE_1BPP,
|
||||
'PDFImage.createImageData: The image must be grayscale.');
|
||||
assert(
|
||||
kind === ImageKind.GRAYSCALE_1BPP,
|
||||
"PDFImage.createImageData: The image must be grayscale."
|
||||
);
|
||||
var buffer = imgData.data;
|
||||
for (var i = 0, ii = buffer.length; i < ii; i++) {
|
||||
buffer[i] ^= 0xff;
|
||||
@ -592,16 +689,20 @@ var PDFImage = (function PDFImageClosure() {
|
||||
if (this.image instanceof JpegStream && !this.smask && !this.mask) {
|
||||
let imageLength = originalHeight * rowBytes;
|
||||
switch (this.colorSpace.name) {
|
||||
case 'DeviceGray':
|
||||
case "DeviceGray":
|
||||
// Avoid truncating the image, since `JpegImage.getData`
|
||||
// will expand the image data when `forceRGB === true`.
|
||||
imageLength *= 3;
|
||||
/* falls through */
|
||||
case 'DeviceRGB':
|
||||
case 'DeviceCMYK':
|
||||
/* falls through */
|
||||
case "DeviceRGB":
|
||||
case "DeviceCMYK":
|
||||
imgData.kind = ImageKind.RGB_24BPP;
|
||||
imgData.data = this.getImageBytes(imageLength,
|
||||
drawWidth, drawHeight, /* forceRGB = */ true);
|
||||
imgData.data = this.getImageBytes(
|
||||
imageLength,
|
||||
drawWidth,
|
||||
drawHeight,
|
||||
/* forceRGB = */ true
|
||||
);
|
||||
return imgData;
|
||||
}
|
||||
}
|
||||
@ -609,8 +710,8 @@ var PDFImage = (function PDFImageClosure() {
|
||||
|
||||
imgArray = this.getImageBytes(originalHeight * rowBytes);
|
||||
// imgArray can be incomplete (e.g. after CCITT fax encoding).
|
||||
var actualHeight = 0 | (imgArray.length / rowBytes *
|
||||
drawHeight / originalHeight);
|
||||
var actualHeight =
|
||||
0 | (((imgArray.length / rowBytes) * drawHeight) / originalHeight);
|
||||
|
||||
var comps = this.getComponents(imgArray);
|
||||
|
||||
@ -629,16 +730,29 @@ var PDFImage = (function PDFImageClosure() {
|
||||
maybeUndoPreblend = true;
|
||||
|
||||
// Color key masking (opacity) must be performed before decoding.
|
||||
this.fillOpacity(imgData.data, drawWidth, drawHeight, actualHeight,
|
||||
comps);
|
||||
this.fillOpacity(
|
||||
imgData.data,
|
||||
drawWidth,
|
||||
drawHeight,
|
||||
actualHeight,
|
||||
comps
|
||||
);
|
||||
}
|
||||
|
||||
if (this.needsDecode) {
|
||||
this.decodeBuffer(comps);
|
||||
}
|
||||
this.colorSpace.fillRgb(imgData.data, originalWidth, originalHeight,
|
||||
drawWidth, drawHeight, actualHeight, bpc, comps,
|
||||
alpha01);
|
||||
this.colorSpace.fillRgb(
|
||||
imgData.data,
|
||||
originalWidth,
|
||||
originalHeight,
|
||||
drawWidth,
|
||||
drawHeight,
|
||||
actualHeight,
|
||||
bpc,
|
||||
comps,
|
||||
alpha01
|
||||
);
|
||||
if (maybeUndoPreblend) {
|
||||
this.undoPreblend(imgData.data, drawWidth, actualHeight);
|
||||
}
|
||||
@ -647,15 +761,20 @@ var PDFImage = (function PDFImageClosure() {
|
||||
},
|
||||
|
||||
fillGrayBuffer(buffer) {
|
||||
if (typeof PDFJSDev === 'undefined' ||
|
||||
PDFJSDev.test('!PRODUCTION || TESTING')) {
|
||||
assert(buffer instanceof Uint8ClampedArray,
|
||||
'PDFImage.fillGrayBuffer: Unsupported "buffer" type.');
|
||||
if (
|
||||
typeof PDFJSDev === "undefined" ||
|
||||
PDFJSDev.test("!PRODUCTION || TESTING")
|
||||
) {
|
||||
assert(
|
||||
buffer instanceof Uint8ClampedArray,
|
||||
'PDFImage.fillGrayBuffer: Unsupported "buffer" type.'
|
||||
);
|
||||
}
|
||||
var numComps = this.numComps;
|
||||
if (numComps !== 1) {
|
||||
throw new FormatError(
|
||||
`Reading gray scale from a color image: ${numComps}`);
|
||||
`Reading gray scale from a color image: ${numComps}`
|
||||
);
|
||||
}
|
||||
|
||||
var width = this.width;
|
||||
@ -680,7 +799,7 @@ var PDFImage = (function PDFImageClosure() {
|
||||
} else {
|
||||
// scale to {0, 255}
|
||||
for (i = 0; i < length; ++i) {
|
||||
buffer[i] = (-comps[i]) & 255;
|
||||
buffer[i] = -comps[i] & 255;
|
||||
}
|
||||
}
|
||||
return;
|
||||
@ -708,6 +827,4 @@ var PDFImage = (function PDFImageClosure() {
|
||||
return PDFImage;
|
||||
})();
|
||||
|
||||
export {
|
||||
PDFImage,
|
||||
};
|
||||
export { PDFImage };
|
||||
|
@ -14,13 +14,18 @@
|
||||
*/
|
||||
/* eslint no-var: error */
|
||||
|
||||
import { ColorSpace } from './colorspace';
|
||||
import { JpegStream } from './jpeg_stream';
|
||||
import { Stream } from './stream';
|
||||
import { ColorSpace } from "./colorspace";
|
||||
import { JpegStream } from "./jpeg_stream";
|
||||
import { Stream } from "./stream";
|
||||
|
||||
class NativeImageDecoder {
|
||||
constructor({ xref, resources, handler, forceDataSchema = false,
|
||||
pdfFunctionFactory, }) {
|
||||
constructor({
|
||||
xref,
|
||||
resources,
|
||||
handler,
|
||||
forceDataSchema = false,
|
||||
pdfFunctionFactory,
|
||||
}) {
|
||||
this.xref = xref;
|
||||
this.resources = resources;
|
||||
this.handler = handler;
|
||||
@ -29,23 +34,36 @@ class NativeImageDecoder {
|
||||
}
|
||||
|
||||
canDecode(image) {
|
||||
return image instanceof JpegStream &&
|
||||
NativeImageDecoder.isDecodable(image, this.xref, this.resources,
|
||||
this.pdfFunctionFactory);
|
||||
return (
|
||||
image instanceof JpegStream &&
|
||||
NativeImageDecoder.isDecodable(
|
||||
image,
|
||||
this.xref,
|
||||
this.resources,
|
||||
this.pdfFunctionFactory
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
decode(image) {
|
||||
// For natively supported JPEGs send them to the main thread for decoding.
|
||||
const dict = image.dict;
|
||||
let colorSpace = dict.get('ColorSpace', 'CS');
|
||||
colorSpace = ColorSpace.parse(colorSpace, this.xref, this.resources,
|
||||
this.pdfFunctionFactory);
|
||||
let colorSpace = dict.get("ColorSpace", "CS");
|
||||
colorSpace = ColorSpace.parse(
|
||||
colorSpace,
|
||||
this.xref,
|
||||
this.resources,
|
||||
this.pdfFunctionFactory
|
||||
);
|
||||
|
||||
return this.handler.sendWithPromise('JpegDecode', [
|
||||
image.getIR(this.forceDataSchema), colorSpace.numComps
|
||||
]).then(function({ data, width, height, }) {
|
||||
return new Stream(data, 0, data.length, dict);
|
||||
});
|
||||
return this.handler
|
||||
.sendWithPromise("JpegDecode", [
|
||||
image.getIR(this.forceDataSchema),
|
||||
colorSpace.numComps,
|
||||
])
|
||||
.then(function({ data, width, height }) {
|
||||
return new Stream(data, 0, data.length, dict);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -54,14 +72,20 @@ class NativeImageDecoder {
|
||||
*/
|
||||
static isSupported(image, xref, res, pdfFunctionFactory) {
|
||||
const dict = image.dict;
|
||||
if (dict.has('DecodeParms') || dict.has('DP')) {
|
||||
if (dict.has("DecodeParms") || dict.has("DP")) {
|
||||
return false;
|
||||
}
|
||||
const cs = ColorSpace.parse(dict.get('ColorSpace', 'CS'), xref, res,
|
||||
pdfFunctionFactory);
|
||||
const cs = ColorSpace.parse(
|
||||
dict.get("ColorSpace", "CS"),
|
||||
xref,
|
||||
res,
|
||||
pdfFunctionFactory
|
||||
);
|
||||
// isDefaultDecode() of DeviceGray and DeviceRGB needs no `bpc` argument.
|
||||
return (cs.name === 'DeviceGray' || cs.name === 'DeviceRGB') &&
|
||||
cs.isDefaultDecode(dict.getArray('Decode', 'D'));
|
||||
return (
|
||||
(cs.name === "DeviceGray" || cs.name === "DeviceRGB") &&
|
||||
cs.isDefaultDecode(dict.getArray("Decode", "D"))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -69,17 +93,21 @@ class NativeImageDecoder {
|
||||
*/
|
||||
static isDecodable(image, xref, res, pdfFunctionFactory) {
|
||||
const dict = image.dict;
|
||||
if (dict.has('DecodeParms') || dict.has('DP')) {
|
||||
if (dict.has("DecodeParms") || dict.has("DP")) {
|
||||
return false;
|
||||
}
|
||||
const cs = ColorSpace.parse(dict.get('ColorSpace', 'CS'), xref, res,
|
||||
pdfFunctionFactory);
|
||||
const bpc = dict.get('BitsPerComponent', 'BPC') || 1;
|
||||
return (cs.numComps === 1 || cs.numComps === 3) &&
|
||||
cs.isDefaultDecode(dict.getArray('Decode', 'D'), bpc);
|
||||
const cs = ColorSpace.parse(
|
||||
dict.get("ColorSpace", "CS"),
|
||||
xref,
|
||||
res,
|
||||
pdfFunctionFactory
|
||||
);
|
||||
const bpc = dict.get("BitsPerComponent", "BPC") || 1;
|
||||
return (
|
||||
(cs.numComps === 1 || cs.numComps === 3) &&
|
||||
cs.isDefaultDecode(dict.getArray("Decode", "D"), bpc)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
NativeImageDecoder,
|
||||
};
|
||||
export { NativeImageDecoder };
|
||||
|
1383
src/core/jbig2.js
1383
src/core/jbig2.js
File diff suppressed because it is too large
Load Diff
@ -13,10 +13,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { isDict, isStream } from './primitives';
|
||||
import { DecodeStream } from './stream';
|
||||
import { Jbig2Image } from './jbig2';
|
||||
import { shadow } from '../shared/util';
|
||||
import { isDict, isStream } from "./primitives";
|
||||
import { DecodeStream } from "./stream";
|
||||
import { Jbig2Image } from "./jbig2";
|
||||
import { shadow } from "../shared/util";
|
||||
|
||||
/**
|
||||
* For JBIG2's we use a library to decode these images and
|
||||
@ -34,10 +34,10 @@ let Jbig2Stream = (function Jbig2StreamClosure() {
|
||||
|
||||
Jbig2Stream.prototype = Object.create(DecodeStream.prototype);
|
||||
|
||||
Object.defineProperty(Jbig2Stream.prototype, 'bytes', {
|
||||
Object.defineProperty(Jbig2Stream.prototype, "bytes", {
|
||||
get() {
|
||||
// If `this.maybeLength` is null, we'll get the entire stream.
|
||||
return shadow(this, 'bytes', this.stream.getBytes(this.maybeLength));
|
||||
return shadow(this, "bytes", this.stream.getBytes(this.maybeLength));
|
||||
},
|
||||
configurable: true,
|
||||
});
|
||||
@ -55,19 +55,19 @@ let Jbig2Stream = (function Jbig2StreamClosure() {
|
||||
|
||||
let chunks = [];
|
||||
if (isDict(this.params)) {
|
||||
let globalsStream = this.params.get('JBIG2Globals');
|
||||
let globalsStream = this.params.get("JBIG2Globals");
|
||||
if (isStream(globalsStream)) {
|
||||
let globals = globalsStream.getBytes();
|
||||
chunks.push({ data: globals, start: 0, end: globals.length, });
|
||||
chunks.push({ data: globals, start: 0, end: globals.length });
|
||||
}
|
||||
}
|
||||
chunks.push({ data: this.bytes, start: 0, end: this.bytes.length, });
|
||||
chunks.push({ data: this.bytes, start: 0, end: this.bytes.length });
|
||||
let data = jbig2Image.parseChunks(chunks);
|
||||
let dataLength = data.length;
|
||||
|
||||
// JBIG2 had black as 1 and white as 0, inverting the colors
|
||||
for (let i = 0; i < dataLength; i++) {
|
||||
data[i] ^= 0xFF;
|
||||
data[i] ^= 0xff;
|
||||
}
|
||||
this.buffer = data;
|
||||
this.bufferLength = dataLength;
|
||||
@ -77,6 +77,4 @@ let Jbig2Stream = (function Jbig2StreamClosure() {
|
||||
return Jbig2Stream;
|
||||
})();
|
||||
|
||||
export {
|
||||
Jbig2Stream,
|
||||
};
|
||||
export { Jbig2Stream };
|
||||
|
@ -13,10 +13,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { createObjectURL, shadow } from '../shared/util';
|
||||
import { DecodeStream } from './stream';
|
||||
import { isDict } from './primitives';
|
||||
import { JpegImage } from './jpg';
|
||||
import { createObjectURL, shadow } from "../shared/util";
|
||||
import { DecodeStream } from "./stream";
|
||||
import { isDict } from "./primitives";
|
||||
import { JpegImage } from "./jpg";
|
||||
|
||||
/**
|
||||
* Depending on the type of JPEG a JpegStream is handled in different ways. For
|
||||
@ -31,7 +31,8 @@ let JpegStream = (function JpegStreamClosure() {
|
||||
// Note: this seems to mainly affect inline images.
|
||||
let ch;
|
||||
while ((ch = stream.getByte()) !== -1) {
|
||||
if (ch === 0xFF) { // Find the first byte of the SOI marker (0xFFD8).
|
||||
// Find the first byte of the SOI marker (0xFFD8).
|
||||
if (ch === 0xff) {
|
||||
stream.skip(-1); // Reset the stream position to the SOI.
|
||||
break;
|
||||
}
|
||||
@ -46,10 +47,10 @@ let JpegStream = (function JpegStreamClosure() {
|
||||
|
||||
JpegStream.prototype = Object.create(DecodeStream.prototype);
|
||||
|
||||
Object.defineProperty(JpegStream.prototype, 'bytes', {
|
||||
Object.defineProperty(JpegStream.prototype, "bytes", {
|
||||
get: function JpegStream_bytes() {
|
||||
// If `this.maybeLength` is null, we'll get the entire stream.
|
||||
return shadow(this, 'bytes', this.stream.getBytes(this.maybeLength));
|
||||
return shadow(this, "bytes", this.stream.getBytes(this.maybeLength));
|
||||
},
|
||||
configurable: true,
|
||||
});
|
||||
@ -69,9 +70,9 @@ let JpegStream = (function JpegStreamClosure() {
|
||||
};
|
||||
|
||||
// Checking if values need to be transformed before conversion.
|
||||
let decodeArr = this.dict.getArray('Decode', 'D');
|
||||
let decodeArr = this.dict.getArray("Decode", "D");
|
||||
if (this.forceRGB && Array.isArray(decodeArr)) {
|
||||
let bitsPerComponent = this.dict.get('BitsPerComponent') || 8;
|
||||
let bitsPerComponent = this.dict.get("BitsPerComponent") || 8;
|
||||
let decodeArrLength = decodeArr.length;
|
||||
let transform = new Int32Array(decodeArrLength);
|
||||
let transformNeeded = false;
|
||||
@ -89,7 +90,7 @@ let JpegStream = (function JpegStreamClosure() {
|
||||
}
|
||||
// Fetching the 'ColorTransform' entry, if it exists.
|
||||
if (isDict(this.params)) {
|
||||
let colorTransform = this.params.get('ColorTransform');
|
||||
let colorTransform = this.params.get("ColorTransform");
|
||||
if (Number.isInteger(colorTransform)) {
|
||||
jpegOptions.colorTransform = colorTransform;
|
||||
}
|
||||
@ -109,12 +110,10 @@ let JpegStream = (function JpegStreamClosure() {
|
||||
};
|
||||
|
||||
JpegStream.prototype.getIR = function(forceDataSchema = false) {
|
||||
return createObjectURL(this.bytes, 'image/jpeg', forceDataSchema);
|
||||
return createObjectURL(this.bytes, "image/jpeg", forceDataSchema);
|
||||
};
|
||||
|
||||
return JpegStream;
|
||||
})();
|
||||
|
||||
export {
|
||||
JpegStream,
|
||||
};
|
||||
export { JpegStream };
|
||||
|
545
src/core/jpg.js
545
src/core/jpg.js
@ -12,9 +12,8 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/* eslint-disable no-multi-spaces */
|
||||
|
||||
import { assert, BaseException, warn } from '../shared/util';
|
||||
import { assert, BaseException, warn } from "../shared/util";
|
||||
|
||||
class JpegError extends BaseException {
|
||||
constructor(msg) {
|
||||
@ -29,7 +28,7 @@ class DNLMarkerError extends BaseException {
|
||||
}
|
||||
}
|
||||
|
||||
class EOIMarkerError extends BaseException { }
|
||||
class EOIMarkerError extends BaseException {}
|
||||
|
||||
/**
|
||||
* This code was forked from https://github.com/notmasteryet/jpgjs.
|
||||
@ -45,6 +44,7 @@ class EOIMarkerError extends BaseException { }
|
||||
*/
|
||||
|
||||
var JpegImage = (function JpegImageClosure() {
|
||||
// prettier-ignore
|
||||
var dctZigZag = new Uint8Array([
|
||||
0,
|
||||
1, 8,
|
||||
@ -63,27 +63,32 @@ var JpegImage = (function JpegImageClosure() {
|
||||
63
|
||||
]);
|
||||
|
||||
var dctCos1 = 4017; // cos(pi/16)
|
||||
var dctSin1 = 799; // sin(pi/16)
|
||||
var dctCos3 = 3406; // cos(3*pi/16)
|
||||
var dctSin3 = 2276; // sin(3*pi/16)
|
||||
var dctCos6 = 1567; // cos(6*pi/16)
|
||||
var dctSin6 = 3784; // sin(6*pi/16)
|
||||
var dctSqrt2 = 5793; // sqrt(2)
|
||||
var dctSqrt1d2 = 2896; // sqrt(2) / 2
|
||||
var dctCos1 = 4017; // cos(pi/16)
|
||||
var dctSin1 = 799; // sin(pi/16)
|
||||
var dctCos3 = 3406; // cos(3*pi/16)
|
||||
var dctSin3 = 2276; // sin(3*pi/16)
|
||||
var dctCos6 = 1567; // cos(6*pi/16)
|
||||
var dctSin6 = 3784; // sin(6*pi/16)
|
||||
var dctSqrt2 = 5793; // sqrt(2)
|
||||
var dctSqrt1d2 = 2896; // sqrt(2) / 2
|
||||
|
||||
function JpegImage({ decodeTransform = null, colorTransform = -1, } = {}) {
|
||||
function JpegImage({ decodeTransform = null, colorTransform = -1 } = {}) {
|
||||
this._decodeTransform = decodeTransform;
|
||||
this._colorTransform = colorTransform;
|
||||
}
|
||||
|
||||
function buildHuffmanTable(codeLengths, values) {
|
||||
var k = 0, code = [], i, j, length = 16;
|
||||
var k = 0,
|
||||
code = [],
|
||||
i,
|
||||
j,
|
||||
length = 16;
|
||||
while (length > 0 && !codeLengths[length - 1]) {
|
||||
length--;
|
||||
}
|
||||
code.push({ children: [], index: 0, });
|
||||
var p = code[0], q;
|
||||
code.push({ children: [], index: 0 });
|
||||
var p = code[0],
|
||||
q;
|
||||
for (i = 0; i < length; i++) {
|
||||
for (j = 0; j < codeLengths[i]; j++) {
|
||||
p = code.pop();
|
||||
@ -94,7 +99,7 @@ var JpegImage = (function JpegImageClosure() {
|
||||
p.index++;
|
||||
code.push(p);
|
||||
while (code.length <= i) {
|
||||
code.push(q = { children: [], index: 0, });
|
||||
code.push((q = { children: [], index: 0 }));
|
||||
p.children[p.index] = q.children;
|
||||
p = q;
|
||||
}
|
||||
@ -102,7 +107,7 @@ var JpegImage = (function JpegImageClosure() {
|
||||
}
|
||||
if (i + 1 < length) {
|
||||
// p here points to last code
|
||||
code.push(q = { children: [], index: 0, });
|
||||
code.push((q = { children: [], index: 0 }));
|
||||
p.children[p.index] = q.children;
|
||||
p = q;
|
||||
}
|
||||
@ -114,13 +119,24 @@ var JpegImage = (function JpegImageClosure() {
|
||||
return 64 * ((component.blocksPerLine + 1) * row + col);
|
||||
}
|
||||
|
||||
function decodeScan(data, offset, frame, components, resetInterval,
|
||||
spectralStart, spectralEnd, successivePrev, successive,
|
||||
parseDNLMarker = false) {
|
||||
function decodeScan(
|
||||
data,
|
||||
offset,
|
||||
frame,
|
||||
components,
|
||||
resetInterval,
|
||||
spectralStart,
|
||||
spectralEnd,
|
||||
successivePrev,
|
||||
successive,
|
||||
parseDNLMarker = false
|
||||
) {
|
||||
var mcusPerLine = frame.mcusPerLine;
|
||||
var progressive = frame.progressive;
|
||||
|
||||
var startOffset = offset, bitsData = 0, bitsCount = 0;
|
||||
var startOffset = offset,
|
||||
bitsData = 0,
|
||||
bitsCount = 0;
|
||||
|
||||
function readBit() {
|
||||
if (bitsCount > 0) {
|
||||
@ -128,22 +144,26 @@ var JpegImage = (function JpegImageClosure() {
|
||||
return (bitsData >> bitsCount) & 1;
|
||||
}
|
||||
bitsData = data[offset++];
|
||||
if (bitsData === 0xFF) {
|
||||
if (bitsData === 0xff) {
|
||||
var nextByte = data[offset++];
|
||||
if (nextByte) {
|
||||
if (nextByte === 0xDC && parseDNLMarker) { // DNL == 0xFFDC
|
||||
if (nextByte === 0xdc && parseDNLMarker) {
|
||||
offset += 2; // Skip data length.
|
||||
const scanLines = (data[offset++] << 8) | data[offset++];
|
||||
if (scanLines > 0 && scanLines !== frame.scanLines) {
|
||||
throw new DNLMarkerError(
|
||||
'Found DNL marker (0xFFDC) while parsing scan data', scanLines);
|
||||
"Found DNL marker (0xFFDC) while parsing scan data",
|
||||
scanLines
|
||||
);
|
||||
}
|
||||
} else if (nextByte === 0xD9) { // EOI == 0xFFD9
|
||||
} else if (nextByte === 0xd9) {
|
||||
throw new EOIMarkerError(
|
||||
'Found EOI marker (0xFFD9) while parsing scan data');
|
||||
"Found EOI marker (0xFFD9) while parsing scan data"
|
||||
);
|
||||
}
|
||||
throw new JpegError(
|
||||
`unexpected marker ${((bitsData << 8) | nextByte).toString(16)}`);
|
||||
`unexpected marker ${((bitsData << 8) | nextByte).toString(16)}`
|
||||
);
|
||||
}
|
||||
// unstuff 0
|
||||
}
|
||||
@ -155,11 +175,11 @@ var JpegImage = (function JpegImageClosure() {
|
||||
var node = tree;
|
||||
while (true) {
|
||||
node = node[readBit()];
|
||||
if (typeof node === 'number') {
|
||||
if (typeof node === "number") {
|
||||
return node;
|
||||
}
|
||||
if (typeof node !== 'object') {
|
||||
throw new JpegError('invalid huffman sequence');
|
||||
if (typeof node !== "object") {
|
||||
throw new JpegError("invalid huffman sequence");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -187,11 +207,12 @@ var JpegImage = (function JpegImageClosure() {
|
||||
function decodeBaseline(component, offset) {
|
||||
var t = decodeHuffman(component.huffmanTableDC);
|
||||
var diff = t === 0 ? 0 : receiveAndExtend(t);
|
||||
component.blockData[offset] = (component.pred += diff);
|
||||
component.blockData[offset] = component.pred += diff;
|
||||
var k = 1;
|
||||
while (k < 64) {
|
||||
var rs = decodeHuffman(component.huffmanTableAC);
|
||||
var s = rs & 15, r = rs >> 4;
|
||||
var s = rs & 15,
|
||||
r = rs >> 4;
|
||||
if (s === 0) {
|
||||
if (r < 15) {
|
||||
break;
|
||||
@ -208,8 +229,8 @@ var JpegImage = (function JpegImageClosure() {
|
||||
|
||||
function decodeDCFirst(component, offset) {
|
||||
var t = decodeHuffman(component.huffmanTableDC);
|
||||
var diff = t === 0 ? 0 : (receiveAndExtend(t) << successive);
|
||||
component.blockData[offset] = (component.pred += diff);
|
||||
var diff = t === 0 ? 0 : receiveAndExtend(t) << successive;
|
||||
component.blockData[offset] = component.pred += diff;
|
||||
}
|
||||
|
||||
function decodeDCSuccessive(component, offset) {
|
||||
@ -222,10 +243,12 @@ var JpegImage = (function JpegImageClosure() {
|
||||
eobrun--;
|
||||
return;
|
||||
}
|
||||
var k = spectralStart, e = spectralEnd;
|
||||
var k = spectralStart,
|
||||
e = spectralEnd;
|
||||
while (k <= e) {
|
||||
var rs = decodeHuffman(component.huffmanTableAC);
|
||||
var s = rs & 15, r = rs >> 4;
|
||||
var s = rs & 15,
|
||||
r = rs >> 4;
|
||||
if (s === 0) {
|
||||
if (r < 15) {
|
||||
eobrun = receive(r) + (1 << r) - 1;
|
||||
@ -242,7 +265,8 @@ var JpegImage = (function JpegImageClosure() {
|
||||
}
|
||||
}
|
||||
|
||||
var successiveACState = 0, successiveACNextValue;
|
||||
var successiveACState = 0,
|
||||
successiveACNextValue;
|
||||
function decodeACSuccessive(component, offset) {
|
||||
var k = spectralStart;
|
||||
var e = spectralEnd;
|
||||
@ -267,7 +291,7 @@ var JpegImage = (function JpegImageClosure() {
|
||||
}
|
||||
} else {
|
||||
if (s !== 1) {
|
||||
throw new JpegError('invalid ACn encoding');
|
||||
throw new JpegError("invalid ACn encoding");
|
||||
}
|
||||
successiveACNextValue = receiveAndExtend(s);
|
||||
successiveACState = r ? 2 : 3;
|
||||
@ -338,7 +362,8 @@ var JpegImage = (function JpegImageClosure() {
|
||||
decodeFn = decodeBaseline;
|
||||
}
|
||||
|
||||
var mcu = 0, fileMarker;
|
||||
var mcu = 0,
|
||||
fileMarker;
|
||||
var mcuExpected;
|
||||
if (componentsLength === 1) {
|
||||
mcuExpected = components[0].blocksPerLine * components[0].blocksPerColumn;
|
||||
@ -349,8 +374,9 @@ var JpegImage = (function JpegImageClosure() {
|
||||
var h, v;
|
||||
while (mcu < mcuExpected) {
|
||||
// reset interval stuff
|
||||
var mcuToRead = resetInterval ?
|
||||
Math.min(mcuExpected - mcu, resetInterval) : mcuExpected;
|
||||
var mcuToRead = resetInterval
|
||||
? Math.min(mcuExpected - mcu, resetInterval)
|
||||
: mcuExpected;
|
||||
for (i = 0; i < componentsLength; i++) {
|
||||
components[i].pred = 0;
|
||||
}
|
||||
@ -387,16 +413,19 @@ var JpegImage = (function JpegImageClosure() {
|
||||
} else if (fileMarker.invalid) {
|
||||
// Some bad images seem to pad Scan blocks with e.g. zero bytes, skip
|
||||
// past those to attempt to find a valid marker (fixes issue4090.pdf).
|
||||
warn('decodeScan - unexpected MCU data, current marker is: ' +
|
||||
fileMarker.invalid);
|
||||
warn(
|
||||
"decodeScan - unexpected MCU data, current marker is: " +
|
||||
fileMarker.invalid
|
||||
);
|
||||
offset = fileMarker.offset;
|
||||
}
|
||||
var marker = fileMarker && fileMarker.marker;
|
||||
if (!marker || marker <= 0xFF00) {
|
||||
throw new JpegError('decodeScan - a valid marker was not found.');
|
||||
if (!marker || marker <= 0xff00) {
|
||||
throw new JpegError("decodeScan - a valid marker was not found.");
|
||||
}
|
||||
|
||||
if (marker >= 0xFFD0 && marker <= 0xFFD7) { // RSTx
|
||||
if (marker >= 0xffd0 && marker <= 0xffd7) {
|
||||
// RSTx
|
||||
offset += 2;
|
||||
} else {
|
||||
break;
|
||||
@ -407,8 +436,10 @@ var JpegImage = (function JpegImageClosure() {
|
||||
// Some images include more Scan blocks than expected, skip past those and
|
||||
// attempt to find the next valid marker (fixes issue8182.pdf).
|
||||
if (fileMarker && fileMarker.invalid) {
|
||||
warn('decodeScan - unexpected Scan data, current marker is: ' +
|
||||
fileMarker.invalid);
|
||||
warn(
|
||||
"decodeScan - unexpected Scan data, current marker is: " +
|
||||
fileMarker.invalid
|
||||
);
|
||||
offset = fileMarker.offset;
|
||||
}
|
||||
|
||||
@ -421,13 +452,14 @@ var JpegImage = (function JpegImageClosure() {
|
||||
// IEEE Intl. Conf. on Acoustics, Speech & Signal Processing, 1989,
|
||||
// 988-991.
|
||||
function quantizeAndInverse(component, blockBufferOffset, p) {
|
||||
var qt = component.quantizationTable, blockData = component.blockData;
|
||||
var qt = component.quantizationTable,
|
||||
blockData = component.blockData;
|
||||
var v0, v1, v2, v3, v4, v5, v6, v7;
|
||||
var p0, p1, p2, p3, p4, p5, p6, p7;
|
||||
var t;
|
||||
|
||||
if (!qt) {
|
||||
throw new JpegError('missing required Quantization Table.');
|
||||
throw new JpegError("missing required Quantization Table.");
|
||||
}
|
||||
|
||||
// inverse DCT on rows
|
||||
@ -480,7 +512,7 @@ var JpegImage = (function JpegImageClosure() {
|
||||
// stage 3
|
||||
v0 = (v0 + v1 + 1) >> 1;
|
||||
v1 = v0 - v1;
|
||||
t = (v2 * dctSin6 + v3 * dctCos6 + 128) >> 8;
|
||||
t = (v2 * dctSin6 + v3 * dctCos6 + 128) >> 8;
|
||||
v2 = (v2 * dctCos6 - v3 * dctSin6 + 128) >> 8;
|
||||
v3 = t;
|
||||
v4 = (v4 + v6 + 1) >> 1;
|
||||
@ -493,10 +525,10 @@ var JpegImage = (function JpegImageClosure() {
|
||||
v3 = v0 - v3;
|
||||
v1 = (v1 + v2 + 1) >> 1;
|
||||
v2 = v1 - v2;
|
||||
t = (v4 * dctSin3 + v7 * dctCos3 + 2048) >> 12;
|
||||
t = (v4 * dctSin3 + v7 * dctCos3 + 2048) >> 12;
|
||||
v4 = (v4 * dctCos3 - v7 * dctSin3 + 2048) >> 12;
|
||||
v7 = t;
|
||||
t = (v5 * dctSin1 + v6 * dctCos1 + 2048) >> 12;
|
||||
t = (v5 * dctSin1 + v6 * dctCos1 + 2048) >> 12;
|
||||
v5 = (v5 * dctCos1 - v6 * dctSin1 + 2048) >> 12;
|
||||
v6 = t;
|
||||
|
||||
@ -514,7 +546,7 @@ var JpegImage = (function JpegImageClosure() {
|
||||
// inverse DCT on columns
|
||||
for (var col = 0; col < 8; ++col) {
|
||||
p0 = p[col];
|
||||
p1 = p[col + 8];
|
||||
p1 = p[col + 8];
|
||||
p2 = p[col + 16];
|
||||
p3 = p[col + 24];
|
||||
p4 = p[col + 32];
|
||||
@ -526,9 +558,9 @@ var JpegImage = (function JpegImageClosure() {
|
||||
if ((p1 | p2 | p3 | p4 | p5 | p6 | p7) === 0) {
|
||||
t = (dctSqrt2 * p0 + 8192) >> 14;
|
||||
// convert to 8 bit
|
||||
t = (t < -2040) ? 0 : (t >= 2024) ? 255 : (t + 2056) >> 4;
|
||||
t = t < -2040 ? 0 : t >= 2024 ? 255 : (t + 2056) >> 4;
|
||||
blockData[blockBufferOffset + col] = t;
|
||||
blockData[blockBufferOffset + col + 8] = t;
|
||||
blockData[blockBufferOffset + col + 8] = t;
|
||||
blockData[blockBufferOffset + col + 16] = t;
|
||||
blockData[blockBufferOffset + col + 24] = t;
|
||||
blockData[blockBufferOffset + col + 32] = t;
|
||||
@ -553,7 +585,7 @@ var JpegImage = (function JpegImageClosure() {
|
||||
// converting to UInt8 range later.
|
||||
v0 = ((v0 + v1 + 1) >> 1) + 4112;
|
||||
v1 = v0 - v1;
|
||||
t = (v2 * dctSin6 + v3 * dctCos6 + 2048) >> 12;
|
||||
t = (v2 * dctSin6 + v3 * dctCos6 + 2048) >> 12;
|
||||
v2 = (v2 * dctCos6 - v3 * dctSin6 + 2048) >> 12;
|
||||
v3 = t;
|
||||
v4 = (v4 + v6 + 1) >> 1;
|
||||
@ -566,10 +598,10 @@ var JpegImage = (function JpegImageClosure() {
|
||||
v3 = v0 - v3;
|
||||
v1 = (v1 + v2 + 1) >> 1;
|
||||
v2 = v1 - v2;
|
||||
t = (v4 * dctSin3 + v7 * dctCos3 + 2048) >> 12;
|
||||
t = (v4 * dctSin3 + v7 * dctCos3 + 2048) >> 12;
|
||||
v4 = (v4 * dctCos3 - v7 * dctSin3 + 2048) >> 12;
|
||||
v7 = t;
|
||||
t = (v5 * dctSin1 + v6 * dctCos1 + 2048) >> 12;
|
||||
t = (v5 * dctSin1 + v6 * dctCos1 + 2048) >> 12;
|
||||
v5 = (v5 * dctCos1 - v6 * dctSin1 + 2048) >> 12;
|
||||
v6 = t;
|
||||
|
||||
@ -584,18 +616,18 @@ var JpegImage = (function JpegImageClosure() {
|
||||
p4 = v3 - v4;
|
||||
|
||||
// convert to 8-bit integers
|
||||
p0 = (p0 < 16) ? 0 : (p0 >= 4080) ? 255 : p0 >> 4;
|
||||
p1 = (p1 < 16) ? 0 : (p1 >= 4080) ? 255 : p1 >> 4;
|
||||
p2 = (p2 < 16) ? 0 : (p2 >= 4080) ? 255 : p2 >> 4;
|
||||
p3 = (p3 < 16) ? 0 : (p3 >= 4080) ? 255 : p3 >> 4;
|
||||
p4 = (p4 < 16) ? 0 : (p4 >= 4080) ? 255 : p4 >> 4;
|
||||
p5 = (p5 < 16) ? 0 : (p5 >= 4080) ? 255 : p5 >> 4;
|
||||
p6 = (p6 < 16) ? 0 : (p6 >= 4080) ? 255 : p6 >> 4;
|
||||
p7 = (p7 < 16) ? 0 : (p7 >= 4080) ? 255 : p7 >> 4;
|
||||
p0 = p0 < 16 ? 0 : p0 >= 4080 ? 255 : p0 >> 4;
|
||||
p1 = p1 < 16 ? 0 : p1 >= 4080 ? 255 : p1 >> 4;
|
||||
p2 = p2 < 16 ? 0 : p2 >= 4080 ? 255 : p2 >> 4;
|
||||
p3 = p3 < 16 ? 0 : p3 >= 4080 ? 255 : p3 >> 4;
|
||||
p4 = p4 < 16 ? 0 : p4 >= 4080 ? 255 : p4 >> 4;
|
||||
p5 = p5 < 16 ? 0 : p5 >= 4080 ? 255 : p5 >> 4;
|
||||
p6 = p6 < 16 ? 0 : p6 >= 4080 ? 255 : p6 >> 4;
|
||||
p7 = p7 < 16 ? 0 : p7 >= 4080 ? 255 : p7 >> 4;
|
||||
|
||||
// store block data
|
||||
blockData[blockBufferOffset + col] = p0;
|
||||
blockData[blockBufferOffset + col + 8] = p1;
|
||||
blockData[blockBufferOffset + col + 8] = p1;
|
||||
blockData[blockBufferOffset + col + 16] = p2;
|
||||
blockData[blockBufferOffset + col + 24] = p3;
|
||||
blockData[blockBufferOffset + col + 32] = p4;
|
||||
@ -631,7 +663,7 @@ var JpegImage = (function JpegImageClosure() {
|
||||
return null; // Don't attempt to read non-existent data and just return.
|
||||
}
|
||||
var currentMarker = peekUint16(currentPos);
|
||||
if (currentMarker >= 0xFFC0 && currentMarker <= 0xFFFE) {
|
||||
if (currentMarker >= 0xffc0 && currentMarker <= 0xfffe) {
|
||||
return {
|
||||
invalid: null,
|
||||
marker: currentMarker,
|
||||
@ -639,7 +671,7 @@ var JpegImage = (function JpegImageClosure() {
|
||||
};
|
||||
}
|
||||
var newMarker = peekUint16(newPos);
|
||||
while (!(newMarker >= 0xFFC0 && newMarker <= 0xFFFE)) {
|
||||
while (!(newMarker >= 0xffc0 && newMarker <= 0xfffe)) {
|
||||
if (++newPos >= maxPos) {
|
||||
return null; // Don't attempt to read non-existent data and just return.
|
||||
}
|
||||
@ -653,8 +685,7 @@ var JpegImage = (function JpegImageClosure() {
|
||||
}
|
||||
|
||||
JpegImage.prototype = {
|
||||
parse(data, { dnlScanLines = null, } = {}) {
|
||||
|
||||
parse(data, { dnlScanLines = null } = {}) {
|
||||
function readUint16() {
|
||||
var value = (data[offset] << 8) | data[offset + 1];
|
||||
offset += 2;
|
||||
@ -667,8 +698,10 @@ var JpegImage = (function JpegImageClosure() {
|
||||
|
||||
var fileMarker = findNextFileMarker(data, endOffset, offset);
|
||||
if (fileMarker && fileMarker.invalid) {
|
||||
warn('readDataBlock - incorrect length, current marker is: ' +
|
||||
fileMarker.invalid);
|
||||
warn(
|
||||
"readDataBlock - incorrect length, current marker is: " +
|
||||
fileMarker.invalid
|
||||
);
|
||||
endOffset = fileMarker.offset;
|
||||
}
|
||||
|
||||
@ -682,15 +715,17 @@ var JpegImage = (function JpegImageClosure() {
|
||||
var mcusPerColumn = Math.ceil(frame.scanLines / 8 / frame.maxV);
|
||||
for (var i = 0; i < frame.components.length; i++) {
|
||||
component = frame.components[i];
|
||||
var blocksPerLine = Math.ceil(Math.ceil(frame.samplesPerLine / 8) *
|
||||
component.h / frame.maxH);
|
||||
var blocksPerColumn = Math.ceil(Math.ceil(frame.scanLines / 8) *
|
||||
component.v / frame.maxV);
|
||||
var blocksPerLine = Math.ceil(
|
||||
(Math.ceil(frame.samplesPerLine / 8) * component.h) / frame.maxH
|
||||
);
|
||||
var blocksPerColumn = Math.ceil(
|
||||
(Math.ceil(frame.scanLines / 8) * component.v) / frame.maxV
|
||||
);
|
||||
var blocksPerLineForMcu = mcusPerLine * component.h;
|
||||
var blocksPerColumnForMcu = mcusPerColumn * component.v;
|
||||
|
||||
var blocksBufferSize = 64 * blocksPerColumnForMcu *
|
||||
(blocksPerLineForMcu + 1);
|
||||
var blocksBufferSize =
|
||||
64 * blocksPerColumnForMcu * (blocksPerLineForMcu + 1);
|
||||
component.blockData = new Int16Array(blocksBufferSize);
|
||||
component.blocksPerLine = blocksPerLine;
|
||||
component.blocksPerColumn = blocksPerColumn;
|
||||
@ -705,56 +740,69 @@ var JpegImage = (function JpegImageClosure() {
|
||||
var frame, resetInterval;
|
||||
let numSOSMarkers = 0;
|
||||
var quantizationTables = [];
|
||||
var huffmanTablesAC = [], huffmanTablesDC = [];
|
||||
var huffmanTablesAC = [],
|
||||
huffmanTablesDC = [];
|
||||
var fileMarker = readUint16();
|
||||
if (fileMarker !== 0xFFD8) { // SOI (Start of Image)
|
||||
throw new JpegError('SOI not found');
|
||||
if (fileMarker !== /* SOI (Start of Image) = */ 0xffd8) {
|
||||
throw new JpegError("SOI not found");
|
||||
}
|
||||
|
||||
fileMarker = readUint16();
|
||||
markerLoop: while (fileMarker !== 0xFFD9) { // EOI (End of image)
|
||||
markerLoop: while (fileMarker !== /* EOI (End of Image) = */ 0xffd9) {
|
||||
var i, j, l;
|
||||
switch (fileMarker) {
|
||||
case 0xFFE0: // APP0 (Application Specific)
|
||||
case 0xFFE1: // APP1
|
||||
case 0xFFE2: // APP2
|
||||
case 0xFFE3: // APP3
|
||||
case 0xFFE4: // APP4
|
||||
case 0xFFE5: // APP5
|
||||
case 0xFFE6: // APP6
|
||||
case 0xFFE7: // APP7
|
||||
case 0xFFE8: // APP8
|
||||
case 0xFFE9: // APP9
|
||||
case 0xFFEA: // APP10
|
||||
case 0xFFEB: // APP11
|
||||
case 0xFFEC: // APP12
|
||||
case 0xFFED: // APP13
|
||||
case 0xFFEE: // APP14
|
||||
case 0xFFEF: // APP15
|
||||
case 0xFFFE: // COM (Comment)
|
||||
case 0xffe0: // APP0 (Application Specific)
|
||||
case 0xffe1: // APP1
|
||||
case 0xffe2: // APP2
|
||||
case 0xffe3: // APP3
|
||||
case 0xffe4: // APP4
|
||||
case 0xffe5: // APP5
|
||||
case 0xffe6: // APP6
|
||||
case 0xffe7: // APP7
|
||||
case 0xffe8: // APP8
|
||||
case 0xffe9: // APP9
|
||||
case 0xffea: // APP10
|
||||
case 0xffeb: // APP11
|
||||
case 0xffec: // APP12
|
||||
case 0xffed: // APP13
|
||||
case 0xffee: // APP14
|
||||
case 0xffef: // APP15
|
||||
case 0xfffe: // COM (Comment)
|
||||
var appData = readDataBlock();
|
||||
|
||||
if (fileMarker === 0xFFE0) {
|
||||
if (appData[0] === 0x4A && appData[1] === 0x46 &&
|
||||
appData[2] === 0x49 && appData[3] === 0x46 &&
|
||||
appData[4] === 0) { // 'JFIF\x00'
|
||||
if (fileMarker === 0xffe0) {
|
||||
// 'JFIF\x00'
|
||||
if (
|
||||
appData[0] === 0x4a &&
|
||||
appData[1] === 0x46 &&
|
||||
appData[2] === 0x49 &&
|
||||
appData[3] === 0x46 &&
|
||||
appData[4] === 0
|
||||
) {
|
||||
jfif = {
|
||||
version: { major: appData[5], minor: appData[6], },
|
||||
version: { major: appData[5], minor: appData[6] },
|
||||
densityUnits: appData[7],
|
||||
xDensity: (appData[8] << 8) | appData[9],
|
||||
yDensity: (appData[10] << 8) | appData[11],
|
||||
thumbWidth: appData[12],
|
||||
thumbHeight: appData[13],
|
||||
thumbData: appData.subarray(14, 14 +
|
||||
3 * appData[12] * appData[13]),
|
||||
thumbData: appData.subarray(
|
||||
14,
|
||||
14 + 3 * appData[12] * appData[13]
|
||||
),
|
||||
};
|
||||
}
|
||||
}
|
||||
// TODO APP1 - Exif
|
||||
if (fileMarker === 0xFFEE) {
|
||||
if (appData[0] === 0x41 && appData[1] === 0x64 &&
|
||||
appData[2] === 0x6F && appData[3] === 0x62 &&
|
||||
appData[4] === 0x65) { // 'Adobe'
|
||||
if (fileMarker === 0xffee) {
|
||||
// 'Adobe'
|
||||
if (
|
||||
appData[0] === 0x41 &&
|
||||
appData[1] === 0x64 &&
|
||||
appData[2] === 0x6f &&
|
||||
appData[3] === 0x62 &&
|
||||
appData[4] === 0x65
|
||||
) {
|
||||
adobe = {
|
||||
version: (appData[5] << 8) | appData[6],
|
||||
flags0: (appData[7] << 8) | appData[8],
|
||||
@ -765,48 +813,52 @@ var JpegImage = (function JpegImageClosure() {
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xFFDB: // DQT (Define Quantization Tables)
|
||||
case 0xffdb: // DQT (Define Quantization Tables)
|
||||
var quantizationTablesLength = readUint16();
|
||||
var quantizationTablesEnd = quantizationTablesLength + offset - 2;
|
||||
var z;
|
||||
while (offset < quantizationTablesEnd) {
|
||||
var quantizationTableSpec = data[offset++];
|
||||
var tableData = new Uint16Array(64);
|
||||
if ((quantizationTableSpec >> 4) === 0) { // 8 bit values
|
||||
if (quantizationTableSpec >> 4 === 0) {
|
||||
// 8 bit values
|
||||
for (j = 0; j < 64; j++) {
|
||||
z = dctZigZag[j];
|
||||
tableData[z] = data[offset++];
|
||||
}
|
||||
} else if ((quantizationTableSpec >> 4) === 1) { // 16 bit values
|
||||
} else if (quantizationTableSpec >> 4 === 1) {
|
||||
// 16 bit values
|
||||
for (j = 0; j < 64; j++) {
|
||||
z = dctZigZag[j];
|
||||
tableData[z] = readUint16();
|
||||
}
|
||||
} else {
|
||||
throw new JpegError('DQT - invalid table spec');
|
||||
throw new JpegError("DQT - invalid table spec");
|
||||
}
|
||||
quantizationTables[quantizationTableSpec & 15] = tableData;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xFFC0: // SOF0 (Start of Frame, Baseline DCT)
|
||||
case 0xFFC1: // SOF1 (Start of Frame, Extended DCT)
|
||||
case 0xFFC2: // SOF2 (Start of Frame, Progressive DCT)
|
||||
case 0xffc0: // SOF0 (Start of Frame, Baseline DCT)
|
||||
case 0xffc1: // SOF1 (Start of Frame, Extended DCT)
|
||||
case 0xffc2: // SOF2 (Start of Frame, Progressive DCT)
|
||||
if (frame) {
|
||||
throw new JpegError('Only single frame JPEGs supported');
|
||||
throw new JpegError("Only single frame JPEGs supported");
|
||||
}
|
||||
readUint16(); // skip data length
|
||||
frame = {};
|
||||
frame.extended = (fileMarker === 0xFFC1);
|
||||
frame.progressive = (fileMarker === 0xFFC2);
|
||||
frame.extended = fileMarker === 0xffc1;
|
||||
frame.progressive = fileMarker === 0xffc2;
|
||||
frame.precision = data[offset++];
|
||||
const sofScanLines = readUint16();
|
||||
frame.scanLines = dnlScanLines || sofScanLines;
|
||||
frame.samplesPerLine = readUint16();
|
||||
frame.components = [];
|
||||
frame.componentIds = {};
|
||||
var componentsCount = data[offset++], componentId;
|
||||
var maxH = 0, maxV = 0;
|
||||
var componentsCount = data[offset++],
|
||||
componentId;
|
||||
var maxH = 0,
|
||||
maxV = 0;
|
||||
for (i = 0; i < componentsCount; i++) {
|
||||
componentId = data[offset];
|
||||
var h = data[offset + 1] >> 4;
|
||||
@ -832,14 +884,14 @@ var JpegImage = (function JpegImageClosure() {
|
||||
prepareComponents(frame);
|
||||
break;
|
||||
|
||||
case 0xFFC4: // DHT (Define Huffman Tables)
|
||||
case 0xffc4: // DHT (Define Huffman Tables)
|
||||
var huffmanLength = readUint16();
|
||||
for (i = 2; i < huffmanLength;) {
|
||||
for (i = 2; i < huffmanLength; ) {
|
||||
var huffmanTableSpec = data[offset++];
|
||||
var codeLengths = new Uint8Array(16);
|
||||
var codeLengthSum = 0;
|
||||
for (j = 0; j < 16; j++, offset++) {
|
||||
codeLengthSum += (codeLengths[j] = data[offset]);
|
||||
codeLengthSum += codeLengths[j] = data[offset];
|
||||
}
|
||||
var huffmanValues = new Uint8Array(codeLengthSum);
|
||||
for (j = 0; j < codeLengthSum; j++, offset++) {
|
||||
@ -847,27 +899,28 @@ var JpegImage = (function JpegImageClosure() {
|
||||
}
|
||||
i += 17 + codeLengthSum;
|
||||
|
||||
((huffmanTableSpec >> 4) === 0 ?
|
||||
huffmanTablesDC : huffmanTablesAC)[huffmanTableSpec & 15] =
|
||||
buildHuffmanTable(codeLengths, huffmanValues);
|
||||
(huffmanTableSpec >> 4 === 0 ? huffmanTablesDC : huffmanTablesAC)[
|
||||
huffmanTableSpec & 15
|
||||
] = buildHuffmanTable(codeLengths, huffmanValues);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xFFDD: // DRI (Define Restart Interval)
|
||||
case 0xffdd: // DRI (Define Restart Interval)
|
||||
readUint16(); // skip data length
|
||||
resetInterval = readUint16();
|
||||
break;
|
||||
|
||||
case 0xFFDA: // SOS (Start of Scan)
|
||||
case 0xffda: // SOS (Start of Scan)
|
||||
// A DNL marker (0xFFDC), if it exists, is only allowed at the end
|
||||
// of the first scan segment and may only occur once in an image.
|
||||
// Furthermore, to prevent an infinite loop, do *not* attempt to
|
||||
// parse DNL markers during re-parsing of the JPEG scan data.
|
||||
const parseDNLMarker = (++numSOSMarkers) === 1 && !dnlScanLines;
|
||||
const parseDNLMarker = ++numSOSMarkers === 1 && !dnlScanLines;
|
||||
|
||||
readUint16(); // scanLength
|
||||
var selectorsCount = data[offset++];
|
||||
var components = [], component;
|
||||
var components = [],
|
||||
component;
|
||||
for (i = 0; i < selectorsCount; i++) {
|
||||
var componentIndex = frame.componentIds[data[offset++]];
|
||||
component = frame.components[componentIndex];
|
||||
@ -880,16 +933,23 @@ var JpegImage = (function JpegImageClosure() {
|
||||
var spectralEnd = data[offset++];
|
||||
var successiveApproximation = data[offset++];
|
||||
try {
|
||||
var processed = decodeScan(data, offset,
|
||||
frame, components, resetInterval,
|
||||
spectralStart, spectralEnd,
|
||||
successiveApproximation >> 4, successiveApproximation & 15,
|
||||
parseDNLMarker);
|
||||
var processed = decodeScan(
|
||||
data,
|
||||
offset,
|
||||
frame,
|
||||
components,
|
||||
resetInterval,
|
||||
spectralStart,
|
||||
spectralEnd,
|
||||
successiveApproximation >> 4,
|
||||
successiveApproximation & 15,
|
||||
parseDNLMarker
|
||||
);
|
||||
offset += processed;
|
||||
} catch (ex) {
|
||||
if (ex instanceof DNLMarkerError) {
|
||||
warn(`${ex.message} -- attempting to re-parse the JPEG image.`);
|
||||
return this.parse(data, { dnlScanLines: ex.scanLines, });
|
||||
return this.parse(data, { dnlScanLines: ex.scanLines });
|
||||
} else if (ex instanceof EOIMarkerError) {
|
||||
warn(`${ex.message} -- ignoring the rest of the image data.`);
|
||||
break markerLoop;
|
||||
@ -898,20 +958,24 @@ var JpegImage = (function JpegImageClosure() {
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xFFDC: // DNL (Define Number of Lines)
|
||||
case 0xffdc: // DNL (Define Number of Lines)
|
||||
// Ignore the marker, since it's being handled in `decodeScan`.
|
||||
offset += 4;
|
||||
break;
|
||||
|
||||
case 0xFFFF: // Fill bytes
|
||||
if (data[offset] !== 0xFF) { // Avoid skipping a valid marker.
|
||||
case 0xffff: // Fill bytes
|
||||
if (data[offset] !== 0xff) {
|
||||
// Avoid skipping a valid marker.
|
||||
offset--;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (data[offset - 3] === 0xFF &&
|
||||
data[offset - 2] >= 0xC0 && data[offset - 2] <= 0xFE) {
|
||||
if (
|
||||
data[offset - 3] === 0xff &&
|
||||
data[offset - 2] >= 0xc0 &&
|
||||
data[offset - 2] <= 0xfe
|
||||
) {
|
||||
// could be incorrect encoding -- last 0xFF byte of the previous
|
||||
// block was eaten by the encoder
|
||||
offset -= 3;
|
||||
@ -919,18 +983,23 @@ var JpegImage = (function JpegImageClosure() {
|
||||
}
|
||||
let nextFileMarker = findNextFileMarker(data, offset - 2);
|
||||
if (nextFileMarker && nextFileMarker.invalid) {
|
||||
warn('JpegImage.parse - unexpected data, current marker is: ' +
|
||||
nextFileMarker.invalid);
|
||||
warn(
|
||||
"JpegImage.parse - unexpected data, current marker is: " +
|
||||
nextFileMarker.invalid
|
||||
);
|
||||
offset = nextFileMarker.offset;
|
||||
break;
|
||||
}
|
||||
if (offset > (data.length - 2)) {
|
||||
warn('JpegImage.parse - reached the end of the image data ' +
|
||||
'without finding an EOI marker (0xFFD9).');
|
||||
if (offset > data.length - 2) {
|
||||
warn(
|
||||
"JpegImage.parse - reached the end of the image data " +
|
||||
"without finding an EOI marker (0xFFD9)."
|
||||
);
|
||||
break markerLoop;
|
||||
}
|
||||
throw new JpegError('JpegImage.parse - unknown marker: ' +
|
||||
fileMarker.toString(16));
|
||||
throw new JpegError(
|
||||
"JpegImage.parse - unknown marker: " + fileMarker.toString(16)
|
||||
);
|
||||
}
|
||||
fileMarker = readUint16();
|
||||
}
|
||||
@ -964,7 +1033,8 @@ var JpegImage = (function JpegImageClosure() {
|
||||
},
|
||||
|
||||
_getLinearizedBlockData(width, height, isSourcePDF = false) {
|
||||
var scaleX = this.width / width, scaleY = this.height / height;
|
||||
var scaleX = this.width / width,
|
||||
scaleY = this.height / height;
|
||||
|
||||
var component, componentScaleX, componentScaleY, blocksPerScanline;
|
||||
var x, y, i, j, k;
|
||||
@ -992,7 +1062,7 @@ var JpegImage = (function JpegImageClosure() {
|
||||
// linearize the blocks of the component
|
||||
for (y = 0; y < height; y++) {
|
||||
j = 0 | (y * componentScaleY);
|
||||
index = blocksPerScanline * (j & mask3LSB) | ((j & 7) << 3);
|
||||
index = (blocksPerScanline * (j & mask3LSB)) | ((j & 7) << 3);
|
||||
for (x = 0; x < width; x++) {
|
||||
data[offset] = output[index + xScaleBlockOffset[x]];
|
||||
offset += numComponents;
|
||||
@ -1015,12 +1085,13 @@ var JpegImage = (function JpegImageClosure() {
|
||||
// inverting JPEG (CMYK) images if and only if the image data does *not*
|
||||
// come from a PDF file and no `decodeTransform` was passed by the user.
|
||||
if (!isSourcePDF && numComponents === 4 && !transform) {
|
||||
// prettier-ignore
|
||||
transform = new Int32Array([
|
||||
-256, 255, -256, 255, -256, 255, -256, 255]);
|
||||
}
|
||||
|
||||
if (transform) {
|
||||
for (i = 0; i < dataLength;) {
|
||||
for (i = 0; i < dataLength; ) {
|
||||
for (j = 0, k = 0; j < numComponents; j++, i++, k += 2) {
|
||||
data[i] = ((data[i] * transform[k]) >> 8) + transform[k + 1];
|
||||
}
|
||||
@ -1075,34 +1146,61 @@ var JpegImage = (function JpegImageClosure() {
|
||||
Cr = data[i + 2];
|
||||
k = data[i + 3];
|
||||
|
||||
data[offset++] = -122.67195406894 +
|
||||
Cb * (-6.60635669420364e-5 * Cb + 0.000437130475926232 * Cr -
|
||||
5.4080610064599e-5 * Y + 0.00048449797120281 * k -
|
||||
0.154362151871126) +
|
||||
Cr * (-0.000957964378445773 * Cr + 0.000817076911346625 * Y -
|
||||
0.00477271405408747 * k + 1.53380253221734) +
|
||||
Y * (0.000961250184130688 * Y - 0.00266257332283933 * k +
|
||||
0.48357088451265) +
|
||||
data[offset++] =
|
||||
-122.67195406894 +
|
||||
Cb *
|
||||
(-6.60635669420364e-5 * Cb +
|
||||
0.000437130475926232 * Cr -
|
||||
5.4080610064599e-5 * Y +
|
||||
0.00048449797120281 * k -
|
||||
0.154362151871126) +
|
||||
Cr *
|
||||
(-0.000957964378445773 * Cr +
|
||||
0.000817076911346625 * Y -
|
||||
0.00477271405408747 * k +
|
||||
1.53380253221734) +
|
||||
Y *
|
||||
(0.000961250184130688 * Y -
|
||||
0.00266257332283933 * k +
|
||||
0.48357088451265) +
|
||||
k * (-0.000336197177618394 * k + 0.484791561490776);
|
||||
|
||||
data[offset++] = 107.268039397724 +
|
||||
Cb * (2.19927104525741e-5 * Cb - 0.000640992018297945 * Cr +
|
||||
0.000659397001245577 * Y + 0.000426105652938837 * k -
|
||||
0.176491792462875) +
|
||||
Cr * (-0.000778269941513683 * Cr + 0.00130872261408275 * Y +
|
||||
0.000770482631801132 * k - 0.151051492775562) +
|
||||
Y * (0.00126935368114843 * Y - 0.00265090189010898 * k +
|
||||
0.25802910206845) +
|
||||
data[offset++] =
|
||||
107.268039397724 +
|
||||
Cb *
|
||||
(2.19927104525741e-5 * Cb -
|
||||
0.000640992018297945 * Cr +
|
||||
0.000659397001245577 * Y +
|
||||
0.000426105652938837 * k -
|
||||
0.176491792462875) +
|
||||
Cr *
|
||||
(-0.000778269941513683 * Cr +
|
||||
0.00130872261408275 * Y +
|
||||
0.000770482631801132 * k -
|
||||
0.151051492775562) +
|
||||
Y *
|
||||
(0.00126935368114843 * Y -
|
||||
0.00265090189010898 * k +
|
||||
0.25802910206845) +
|
||||
k * (-0.000318913117588328 * k - 0.213742400323665);
|
||||
|
||||
data[offset++] = -20.810012546947 +
|
||||
Cb * (-0.000570115196973677 * Cb - 2.63409051004589e-5 * Cr +
|
||||
0.0020741088115012 * Y - 0.00288260236853442 * k +
|
||||
0.814272968359295) +
|
||||
Cr * (-1.53496057440975e-5 * Cr - 0.000132689043961446 * Y +
|
||||
0.000560833691242812 * k - 0.195152027534049) +
|
||||
Y * (0.00174418132927582 * Y - 0.00255243321439347 * k +
|
||||
0.116935020465145) +
|
||||
data[offset++] =
|
||||
-20.810012546947 +
|
||||
Cb *
|
||||
(-0.000570115196973677 * Cb -
|
||||
2.63409051004589e-5 * Cr +
|
||||
0.0020741088115012 * Y -
|
||||
0.00288260236853442 * k +
|
||||
0.814272968359295) +
|
||||
Cr *
|
||||
(-1.53496057440975e-5 * Cr -
|
||||
0.000132689043961446 * Y +
|
||||
0.000560833691242812 * k -
|
||||
0.195152027534049) +
|
||||
Y *
|
||||
(0.00174418132927582 * Y -
|
||||
0.00255243321439347 * k +
|
||||
0.116935020465145) +
|
||||
k * (-0.000343531996510555 * k + 0.24165260232407);
|
||||
}
|
||||
// Ensure that only the converted RGB data is returned.
|
||||
@ -1133,47 +1231,74 @@ var JpegImage = (function JpegImageClosure() {
|
||||
y = data[i + 2] * scale;
|
||||
k = data[i + 3] * scale;
|
||||
|
||||
data[offset++] = 255 +
|
||||
c * (-4.387332384609988 * c + 54.48615194189176 * m +
|
||||
18.82290502165302 * y + 212.25662451639585 * k -
|
||||
285.2331026137004) +
|
||||
m * (1.7149763477362134 * m - 5.6096736904047315 * y -
|
||||
17.873870861415444 * k - 5.497006427196366) +
|
||||
y * (-2.5217340131683033 * y - 21.248923337353073 * k +
|
||||
17.5119270841813) -
|
||||
data[offset++] =
|
||||
255 +
|
||||
c *
|
||||
(-4.387332384609988 * c +
|
||||
54.48615194189176 * m +
|
||||
18.82290502165302 * y +
|
||||
212.25662451639585 * k -
|
||||
285.2331026137004) +
|
||||
m *
|
||||
(1.7149763477362134 * m -
|
||||
5.6096736904047315 * y -
|
||||
17.873870861415444 * k -
|
||||
5.497006427196366) +
|
||||
y *
|
||||
(-2.5217340131683033 * y -
|
||||
21.248923337353073 * k +
|
||||
17.5119270841813) -
|
||||
k * (21.86122147463605 * k + 189.48180835922747);
|
||||
|
||||
data[offset++] = 255 +
|
||||
c * (8.841041422036149 * c + 60.118027045597366 * m +
|
||||
6.871425592049007 * y + 31.159100130055922 * k -
|
||||
79.2970844816548) +
|
||||
m * (-15.310361306967817 * m + 17.575251261109482 * y +
|
||||
131.35250912493976 * k - 190.9453302588951) +
|
||||
y * (4.444339102852739 * y + 9.8632861493405 * k -
|
||||
24.86741582555878) -
|
||||
data[offset++] =
|
||||
255 +
|
||||
c *
|
||||
(8.841041422036149 * c +
|
||||
60.118027045597366 * m +
|
||||
6.871425592049007 * y +
|
||||
31.159100130055922 * k -
|
||||
79.2970844816548) +
|
||||
m *
|
||||
(-15.310361306967817 * m +
|
||||
17.575251261109482 * y +
|
||||
131.35250912493976 * k -
|
||||
190.9453302588951) +
|
||||
y *
|
||||
(4.444339102852739 * y + 9.8632861493405 * k - 24.86741582555878) -
|
||||
k * (20.737325471181034 * k + 187.80453709719578);
|
||||
|
||||
data[offset++] = 255 +
|
||||
c * (0.8842522430003296 * c + 8.078677503112928 * m +
|
||||
30.89978309703729 * y - 0.23883238689178934 * k -
|
||||
14.183576799673286) +
|
||||
m * (10.49593273432072 * m + 63.02378494754052 * y +
|
||||
50.606957656360734 * k - 112.23884253719248) +
|
||||
y * (0.03296041114873217 * y + 115.60384449646641 * k -
|
||||
193.58209356861505) -
|
||||
data[offset++] =
|
||||
255 +
|
||||
c *
|
||||
(0.8842522430003296 * c +
|
||||
8.078677503112928 * m +
|
||||
30.89978309703729 * y -
|
||||
0.23883238689178934 * k -
|
||||
14.183576799673286) +
|
||||
m *
|
||||
(10.49593273432072 * m +
|
||||
63.02378494754052 * y +
|
||||
50.606957656360734 * k -
|
||||
112.23884253719248) +
|
||||
y *
|
||||
(0.03296041114873217 * y +
|
||||
115.60384449646641 * k -
|
||||
193.58209356861505) -
|
||||
k * (22.33816807309886 * k + 180.12613974708367);
|
||||
}
|
||||
// Ensure that only the converted RGB data is returned.
|
||||
return data.subarray(0, offset);
|
||||
},
|
||||
|
||||
getData({ width, height, forceRGB = false, isSourcePDF = false, }) {
|
||||
if (typeof PDFJSDev !== 'undefined' && PDFJSDev.test('TESTING && !LIB')) {
|
||||
assert(isSourcePDF === true,
|
||||
'JpegImage.getData: Unexpected "isSourcePDF" value for PDF files.');
|
||||
getData({ width, height, forceRGB = false, isSourcePDF = false }) {
|
||||
if (typeof PDFJSDev !== "undefined" && PDFJSDev.test("TESTING && !LIB")) {
|
||||
assert(
|
||||
isSourcePDF === true,
|
||||
'JpegImage.getData: Unexpected "isSourcePDF" value for PDF files.'
|
||||
);
|
||||
}
|
||||
if (this.numComponents > 4) {
|
||||
throw new JpegError('Unsupported color mode');
|
||||
throw new JpegError("Unsupported color mode");
|
||||
}
|
||||
// Type of data: Uint8ClampedArray(width * height * numComponents)
|
||||
var data = this._getLinearizedBlockData(width, height, isSourcePDF);
|
||||
@ -1208,6 +1333,4 @@ var JpegImage = (function JpegImageClosure() {
|
||||
return JpegImage;
|
||||
})();
|
||||
|
||||
export {
|
||||
JpegImage,
|
||||
};
|
||||
export { JpegImage };
|
||||
|
634
src/core/jpx.js
634
src/core/jpx.js
File diff suppressed because it is too large
Load Diff
@ -13,9 +13,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { DecodeStream } from './stream';
|
||||
import { JpxImage } from './jpx';
|
||||
import { shadow } from '../shared/util';
|
||||
import { DecodeStream } from "./stream";
|
||||
import { JpxImage } from "./jpx";
|
||||
import { shadow } from "../shared/util";
|
||||
|
||||
/**
|
||||
* For JPEG 2000's we use a library to decode these images and
|
||||
@ -33,10 +33,10 @@ let JpxStream = (function JpxStreamClosure() {
|
||||
|
||||
JpxStream.prototype = Object.create(DecodeStream.prototype);
|
||||
|
||||
Object.defineProperty(JpxStream.prototype, 'bytes', {
|
||||
Object.defineProperty(JpxStream.prototype, "bytes", {
|
||||
get: function JpxStream_bytes() {
|
||||
// If `this.maybeLength` is null, we'll get the entire stream.
|
||||
return shadow(this, 'bytes', this.stream.getBytes(this.maybeLength));
|
||||
return shadow(this, "bytes", this.stream.getBytes(this.maybeLength));
|
||||
},
|
||||
configurable: true,
|
||||
});
|
||||
@ -91,6 +91,4 @@ let JpxStream = (function JpxStreamClosure() {
|
||||
return JpxStream;
|
||||
})();
|
||||
|
||||
export {
|
||||
JpxStream,
|
||||
};
|
||||
export { JpxStream };
|
||||
|
5860
src/core/metrics.js
5860
src/core/metrics.js
File diff suppressed because it is too large
Load Diff
@ -18,7 +18,7 @@
|
||||
*/
|
||||
/* eslint no-var: error */
|
||||
|
||||
import { isArrayBuffer, isString } from '../shared/util';
|
||||
import { isArrayBuffer, isString } from "../shared/util";
|
||||
|
||||
const SEED = 0xc3d2e1f0;
|
||||
// Workaround for missing math precision in JS.
|
||||
@ -49,35 +49,41 @@ class MurmurHash3_64 {
|
||||
data = input;
|
||||
length = data.byteLength;
|
||||
} else {
|
||||
throw new Error('Wrong data format in MurmurHash3_64_update. ' +
|
||||
'Input must be a string or array.');
|
||||
throw new Error(
|
||||
"Wrong data format in MurmurHash3_64_update. " +
|
||||
"Input must be a string or array."
|
||||
);
|
||||
}
|
||||
|
||||
const blockCounts = length >> 2;
|
||||
const tailLength = length - blockCounts * 4;
|
||||
// We don't care about endianness here.
|
||||
const dataUint32 = new Uint32Array(data.buffer, 0, blockCounts);
|
||||
let k1 = 0, k2 = 0;
|
||||
let h1 = this.h1, h2 = this.h2;
|
||||
const C1 = 0xcc9e2d51, C2 = 0x1b873593;
|
||||
const C1_LOW = C1 & MASK_LOW, C2_LOW = C2 & MASK_LOW;
|
||||
let k1 = 0,
|
||||
k2 = 0;
|
||||
let h1 = this.h1,
|
||||
h2 = this.h2;
|
||||
const C1 = 0xcc9e2d51,
|
||||
C2 = 0x1b873593;
|
||||
const C1_LOW = C1 & MASK_LOW,
|
||||
C2_LOW = C2 & MASK_LOW;
|
||||
|
||||
for (let i = 0; i < blockCounts; i++) {
|
||||
if (i & 1) {
|
||||
k1 = dataUint32[i];
|
||||
k1 = (k1 * C1 & MASK_HIGH) | (k1 * C1_LOW & MASK_LOW);
|
||||
k1 = k1 << 15 | k1 >>> 17;
|
||||
k1 = (k1 * C2 & MASK_HIGH) | (k1 * C2_LOW & MASK_LOW);
|
||||
k1 = ((k1 * C1) & MASK_HIGH) | ((k1 * C1_LOW) & MASK_LOW);
|
||||
k1 = (k1 << 15) | (k1 >>> 17);
|
||||
k1 = ((k1 * C2) & MASK_HIGH) | ((k1 * C2_LOW) & MASK_LOW);
|
||||
h1 ^= k1;
|
||||
h1 = h1 << 13 | h1 >>> 19;
|
||||
h1 = (h1 << 13) | (h1 >>> 19);
|
||||
h1 = h1 * 5 + 0xe6546b64;
|
||||
} else {
|
||||
k2 = dataUint32[i];
|
||||
k2 = (k2 * C1 & MASK_HIGH) | (k2 * C1_LOW & MASK_LOW);
|
||||
k2 = k2 << 15 | k2 >>> 17;
|
||||
k2 = (k2 * C2 & MASK_HIGH) | (k2 * C2_LOW & MASK_LOW);
|
||||
k2 = ((k2 * C1) & MASK_HIGH) | ((k2 * C1_LOW) & MASK_LOW);
|
||||
k2 = (k2 << 15) | (k2 >>> 17);
|
||||
k2 = ((k2 * C2) & MASK_HIGH) | ((k2 * C2_LOW) & MASK_LOW);
|
||||
h2 ^= k2;
|
||||
h2 = h2 << 13 | h2 >>> 19;
|
||||
h2 = (h2 << 13) | (h2 >>> 19);
|
||||
h2 = h2 * 5 + 0xe6546b64;
|
||||
}
|
||||
}
|
||||
@ -87,17 +93,17 @@ class MurmurHash3_64 {
|
||||
switch (tailLength) {
|
||||
case 3:
|
||||
k1 ^= data[blockCounts * 4 + 2] << 16;
|
||||
/* falls through */
|
||||
/* falls through */
|
||||
case 2:
|
||||
k1 ^= data[blockCounts * 4 + 1] << 8;
|
||||
/* falls through */
|
||||
/* falls through */
|
||||
case 1:
|
||||
k1 ^= data[blockCounts * 4];
|
||||
/* falls through */
|
||||
|
||||
k1 = (k1 * C1 & MASK_HIGH) | (k1 * C1_LOW & MASK_LOW);
|
||||
k1 = k1 << 15 | k1 >>> 17;
|
||||
k1 = (k1 * C2 & MASK_HIGH) | (k1 * C2_LOW & MASK_LOW);
|
||||
k1 = ((k1 * C1) & MASK_HIGH) | ((k1 * C1_LOW) & MASK_LOW);
|
||||
k1 = (k1 << 15) | (k1 >>> 17);
|
||||
k1 = ((k1 * C2) & MASK_HIGH) | ((k1 * C2_LOW) & MASK_LOW);
|
||||
if (blockCounts & 1) {
|
||||
h1 ^= k1;
|
||||
} else {
|
||||
@ -110,23 +116,25 @@ class MurmurHash3_64 {
|
||||
}
|
||||
|
||||
hexdigest() {
|
||||
let h1 = this.h1, h2 = this.h2;
|
||||
let h1 = this.h1,
|
||||
h2 = this.h2;
|
||||
|
||||
h1 ^= h2 >>> 1;
|
||||
h1 = (h1 * 0xed558ccd & MASK_HIGH) | (h1 * 0x8ccd & MASK_LOW);
|
||||
h2 = (h2 * 0xff51afd7 & MASK_HIGH) |
|
||||
(((h2 << 16 | h1 >>> 16) * 0xafd7ed55 & MASK_HIGH) >>> 16);
|
||||
h1 = ((h1 * 0xed558ccd) & MASK_HIGH) | ((h1 * 0x8ccd) & MASK_LOW);
|
||||
h2 =
|
||||
((h2 * 0xff51afd7) & MASK_HIGH) |
|
||||
(((((h2 << 16) | (h1 >>> 16)) * 0xafd7ed55) & MASK_HIGH) >>> 16);
|
||||
h1 ^= h2 >>> 1;
|
||||
h1 = (h1 * 0x1a85ec53 & MASK_HIGH) | (h1 * 0xec53 & MASK_LOW);
|
||||
h2 = (h2 * 0xc4ceb9fe & MASK_HIGH) |
|
||||
(((h2 << 16 | h1 >>> 16) * 0xb9fe1a85 & MASK_HIGH) >>> 16);
|
||||
h1 = ((h1 * 0x1a85ec53) & MASK_HIGH) | ((h1 * 0xec53) & MASK_LOW);
|
||||
h2 =
|
||||
((h2 * 0xc4ceb9fe) & MASK_HIGH) |
|
||||
(((((h2 << 16) | (h1 >>> 16)) * 0xb9fe1a85) & MASK_HIGH) >>> 16);
|
||||
h1 ^= h2 >>> 1;
|
||||
|
||||
const hex1 = (h1 >>> 0).toString(16), hex2 = (h2 >>> 0).toString(16);
|
||||
return hex1.padStart(8, '0') + hex2.padStart(8, '0');
|
||||
const hex1 = (h1 >>> 0).toString(16),
|
||||
hex2 = (h2 >>> 0).toString(16);
|
||||
return hex1.padStart(8, "0") + hex2.padStart(8, "0");
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
MurmurHash3_64,
|
||||
};
|
||||
export { MurmurHash3_64 };
|
||||
|
993
src/core/obj.js
993
src/core/obj.js
File diff suppressed because it is too large
Load Diff
@ -14,14 +14,14 @@
|
||||
*/
|
||||
/* eslint-disable no-unsanitized/method */
|
||||
|
||||
import { assert, ImageKind, OPS } from '../shared/util';
|
||||
import { assert, ImageKind, OPS } from "../shared/util";
|
||||
|
||||
var QueueOptimizer = (function QueueOptimizerClosure() {
|
||||
function addState(parentState, pattern, checkFn, iterateFn, processFn) {
|
||||
var state = parentState;
|
||||
for (var i = 0, ii = pattern.length - 1; i < ii; i++) {
|
||||
var item = pattern[i];
|
||||
state = (state[item] || (state[item] = []));
|
||||
state = state[item] || (state[item] = []);
|
||||
}
|
||||
state[pattern[pattern.length - 1]] = {
|
||||
checkFn,
|
||||
@ -30,8 +30,12 @@ var QueueOptimizer = (function QueueOptimizerClosure() {
|
||||
};
|
||||
}
|
||||
|
||||
function handlePaintSolidColorImageMask(iFirstSave, count, fnArray,
|
||||
argsArray) {
|
||||
function handlePaintSolidColorImageMask(
|
||||
iFirstSave,
|
||||
count,
|
||||
fnArray,
|
||||
argsArray
|
||||
) {
|
||||
// Handles special case of mainly LaTeX documents which use image masks to
|
||||
// draw lines with the current fill style.
|
||||
// 'count' groups of (save, transform, paintImageMaskXObject, restore)+
|
||||
@ -40,9 +44,13 @@ var QueueOptimizer = (function QueueOptimizerClosure() {
|
||||
for (var i = 0; i < count; i++) {
|
||||
var arg = argsArray[iFirstPIMXO + 4 * i];
|
||||
var imageMask = arg.length === 1 && arg[0];
|
||||
if (imageMask && imageMask.width === 1 && imageMask.height === 1 &&
|
||||
(!imageMask.data.length ||
|
||||
(imageMask.data.length === 1 && imageMask.data[0] === 0))) {
|
||||
if (
|
||||
imageMask &&
|
||||
imageMask.width === 1 &&
|
||||
imageMask.height === 1 &&
|
||||
(!imageMask.data.length ||
|
||||
(imageMask.data.length === 1 && imageMask.data[0] === 0))
|
||||
) {
|
||||
fnArray[iFirstPIMXO + 4 * i] = OPS.paintSolidColorImageMask;
|
||||
continue;
|
||||
}
|
||||
@ -55,7 +63,8 @@ var QueueOptimizer = (function QueueOptimizerClosure() {
|
||||
|
||||
// This replaces (save, transform, paintInlineImageXObject, restore)+
|
||||
// sequences with one |paintInlineImageXObjectGroup| operation.
|
||||
addState(InitialState,
|
||||
addState(
|
||||
InitialState,
|
||||
[OPS.save, OPS.transform, OPS.paintInlineImageXObject, OPS.restore],
|
||||
null,
|
||||
function iterateInlineImageGroup(context, i) {
|
||||
@ -80,23 +89,28 @@ var QueueOptimizer = (function QueueOptimizerClosure() {
|
||||
var MAX_WIDTH = 1000;
|
||||
var IMAGE_PADDING = 1;
|
||||
|
||||
var fnArray = context.fnArray, argsArray = context.argsArray;
|
||||
var fnArray = context.fnArray,
|
||||
argsArray = context.argsArray;
|
||||
var curr = context.iCurr;
|
||||
var iFirstSave = curr - 3;
|
||||
var iFirstTransform = curr - 2;
|
||||
var iFirstPIIXO = curr - 1;
|
||||
|
||||
var count = Math.min(Math.floor((i - iFirstSave) / 4),
|
||||
MAX_IMAGES_IN_INLINE_IMAGES_BLOCK);
|
||||
var count = Math.min(
|
||||
Math.floor((i - iFirstSave) / 4),
|
||||
MAX_IMAGES_IN_INLINE_IMAGES_BLOCK
|
||||
);
|
||||
if (count < MIN_IMAGES_IN_INLINE_IMAGES_BLOCK) {
|
||||
return i - (i - iFirstSave) % 4;
|
||||
return i - ((i - iFirstSave) % 4);
|
||||
}
|
||||
|
||||
// assuming that heights of those image is too small (~1 pixel)
|
||||
// packing as much as possible by lines
|
||||
var maxX = 0;
|
||||
var map = [], maxLineHeight = 0;
|
||||
var currentX = IMAGE_PADDING, currentY = IMAGE_PADDING;
|
||||
var map = [],
|
||||
maxLineHeight = 0;
|
||||
var currentX = IMAGE_PADDING,
|
||||
currentY = IMAGE_PADDING;
|
||||
var q;
|
||||
for (q = 0; q < count; q++) {
|
||||
var transform = argsArray[iFirstTransform + (q << 2)];
|
||||
@ -110,8 +124,10 @@ var QueueOptimizer = (function QueueOptimizerClosure() {
|
||||
}
|
||||
map.push({
|
||||
transform,
|
||||
x: currentX, y: currentY,
|
||||
w: img.width, h: img.height,
|
||||
x: currentX,
|
||||
y: currentY,
|
||||
w: img.width,
|
||||
h: img.height,
|
||||
});
|
||||
currentX += img.width + 2 * IMAGE_PADDING;
|
||||
maxLineHeight = Math.max(maxLineHeight, img.height);
|
||||
@ -148,17 +164,25 @@ var QueueOptimizer = (function QueueOptimizerClosure() {
|
||||
|
||||
// Replace queue items.
|
||||
fnArray.splice(iFirstSave, count * 4, OPS.paintInlineImageXObjectGroup);
|
||||
argsArray.splice(iFirstSave, count * 4,
|
||||
[{ width: imgWidth, height: imgHeight, kind: ImageKind.RGBA_32BPP,
|
||||
data: imgData, }, map]);
|
||||
argsArray.splice(iFirstSave, count * 4, [
|
||||
{
|
||||
width: imgWidth,
|
||||
height: imgHeight,
|
||||
kind: ImageKind.RGBA_32BPP,
|
||||
data: imgData,
|
||||
},
|
||||
map,
|
||||
]);
|
||||
|
||||
return iFirstSave + 1;
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
// This replaces (save, transform, paintImageMaskXObject, restore)+
|
||||
// sequences with one |paintImageMaskXObjectGroup| or one
|
||||
// |paintImageMaskXObjectRepeat| operation.
|
||||
addState(InitialState,
|
||||
addState(
|
||||
InitialState,
|
||||
[OPS.save, OPS.transform, OPS.paintImageMaskXObject, OPS.restore],
|
||||
null,
|
||||
function iterateImageMaskGroup(context, i) {
|
||||
@ -182,7 +206,8 @@ var QueueOptimizer = (function QueueOptimizerClosure() {
|
||||
var MAX_IMAGES_IN_MASKS_BLOCK = 100;
|
||||
var MAX_SAME_IMAGES_IN_MASKS_BLOCK = 1000;
|
||||
|
||||
var fnArray = context.fnArray, argsArray = context.argsArray;
|
||||
var fnArray = context.fnArray,
|
||||
argsArray = context.argsArray;
|
||||
var curr = context.iCurr;
|
||||
var iFirstSave = curr - 3;
|
||||
var iFirstTransform = curr - 2;
|
||||
@ -191,18 +216,24 @@ var QueueOptimizer = (function QueueOptimizerClosure() {
|
||||
// At this point, i is the index of the first op past the last valid
|
||||
// quartet.
|
||||
var count = Math.floor((i - iFirstSave) / 4);
|
||||
count = handlePaintSolidColorImageMask(iFirstSave, count, fnArray,
|
||||
argsArray);
|
||||
count = handlePaintSolidColorImageMask(
|
||||
iFirstSave,
|
||||
count,
|
||||
fnArray,
|
||||
argsArray
|
||||
);
|
||||
if (count < MIN_IMAGES_IN_MASKS_BLOCK) {
|
||||
return i - (i - iFirstSave) % 4;
|
||||
return i - ((i - iFirstSave) % 4);
|
||||
}
|
||||
|
||||
var q;
|
||||
var isSameImage = false;
|
||||
var iTransform, transformArgs;
|
||||
var firstPIMXOArg0 = argsArray[iFirstPIMXO][0];
|
||||
if (argsArray[iFirstTransform][1] === 0 &&
|
||||
argsArray[iFirstTransform][2] === 0) {
|
||||
if (
|
||||
argsArray[iFirstTransform][1] === 0 &&
|
||||
argsArray[iFirstTransform][2] === 0
|
||||
) {
|
||||
isSameImage = true;
|
||||
var firstTransformArg0 = argsArray[iFirstTransform][0];
|
||||
var firstTransformArg3 = argsArray[iFirstTransform][3];
|
||||
@ -210,11 +241,13 @@ var QueueOptimizer = (function QueueOptimizerClosure() {
|
||||
var iPIMXO = iFirstPIMXO + 4;
|
||||
for (q = 1; q < count; q++, iTransform += 4, iPIMXO += 4) {
|
||||
transformArgs = argsArray[iTransform];
|
||||
if (argsArray[iPIMXO][0] !== firstPIMXOArg0 ||
|
||||
transformArgs[0] !== firstTransformArg0 ||
|
||||
transformArgs[1] !== 0 ||
|
||||
transformArgs[2] !== 0 ||
|
||||
transformArgs[3] !== firstTransformArg3) {
|
||||
if (
|
||||
argsArray[iPIMXO][0] !== firstPIMXOArg0 ||
|
||||
transformArgs[0] !== firstTransformArg0 ||
|
||||
transformArgs[1] !== 0 ||
|
||||
transformArgs[2] !== 0 ||
|
||||
transformArgs[3] !== firstTransformArg3
|
||||
) {
|
||||
if (q < MIN_IMAGES_IN_MASKS_BLOCK) {
|
||||
isSameImage = false;
|
||||
} else {
|
||||
@ -231,23 +264,30 @@ var QueueOptimizer = (function QueueOptimizerClosure() {
|
||||
iTransform = iFirstTransform;
|
||||
for (q = 0; q < count; q++, iTransform += 4) {
|
||||
transformArgs = argsArray[iTransform];
|
||||
positions[(q << 1)] = transformArgs[4];
|
||||
positions[q << 1] = transformArgs[4];
|
||||
positions[(q << 1) + 1] = transformArgs[5];
|
||||
}
|
||||
|
||||
// Replace queue items.
|
||||
fnArray.splice(iFirstSave, count * 4, OPS.paintImageMaskXObjectRepeat);
|
||||
argsArray.splice(iFirstSave, count * 4,
|
||||
[firstPIMXOArg0, firstTransformArg0, firstTransformArg3, positions]);
|
||||
argsArray.splice(iFirstSave, count * 4, [
|
||||
firstPIMXOArg0,
|
||||
firstTransformArg0,
|
||||
firstTransformArg3,
|
||||
positions,
|
||||
]);
|
||||
} else {
|
||||
count = Math.min(count, MAX_IMAGES_IN_MASKS_BLOCK);
|
||||
var images = [];
|
||||
for (q = 0; q < count; q++) {
|
||||
transformArgs = argsArray[iFirstTransform + (q << 2)];
|
||||
var maskParams = argsArray[iFirstPIMXO + (q << 2)][0];
|
||||
images.push({ data: maskParams.data, width: maskParams.width,
|
||||
height: maskParams.height,
|
||||
transform: transformArgs, });
|
||||
images.push({
|
||||
data: maskParams.data,
|
||||
width: maskParams.width,
|
||||
height: maskParams.height,
|
||||
transform: transformArgs,
|
||||
});
|
||||
}
|
||||
|
||||
// Replace queue items.
|
||||
@ -256,21 +296,26 @@ var QueueOptimizer = (function QueueOptimizerClosure() {
|
||||
}
|
||||
|
||||
return iFirstSave + 1;
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
// This replaces (save, transform, paintImageXObject, restore)+ sequences
|
||||
// with one paintImageXObjectRepeat operation, if the |transform| and
|
||||
// |paintImageXObjectRepeat| ops are appropriate.
|
||||
addState(InitialState,
|
||||
addState(
|
||||
InitialState,
|
||||
[OPS.save, OPS.transform, OPS.paintImageXObject, OPS.restore],
|
||||
function (context) {
|
||||
function(context) {
|
||||
var argsArray = context.argsArray;
|
||||
var iFirstTransform = context.iCurr - 2;
|
||||
return argsArray[iFirstTransform][1] === 0 &&
|
||||
argsArray[iFirstTransform][2] === 0;
|
||||
return (
|
||||
argsArray[iFirstTransform][1] === 0 &&
|
||||
argsArray[iFirstTransform][2] === 0
|
||||
);
|
||||
},
|
||||
function iterateImageGroup(context, i) {
|
||||
var fnArray = context.fnArray, argsArray = context.argsArray;
|
||||
var fnArray = context.fnArray,
|
||||
argsArray = context.argsArray;
|
||||
var iFirstSave = context.iCurr - 3;
|
||||
var pos = (i - iFirstSave) % 4;
|
||||
switch (pos) {
|
||||
@ -283,10 +328,12 @@ var QueueOptimizer = (function QueueOptimizerClosure() {
|
||||
var iFirstTransform = context.iCurr - 2;
|
||||
var firstTransformArg0 = argsArray[iFirstTransform][0];
|
||||
var firstTransformArg3 = argsArray[iFirstTransform][3];
|
||||
if (argsArray[i][0] !== firstTransformArg0 ||
|
||||
argsArray[i][1] !== 0 ||
|
||||
argsArray[i][2] !== 0 ||
|
||||
argsArray[i][3] !== firstTransformArg3) {
|
||||
if (
|
||||
argsArray[i][0] !== firstTransformArg0 ||
|
||||
argsArray[i][1] !== 0 ||
|
||||
argsArray[i][2] !== 0 ||
|
||||
argsArray[i][3] !== firstTransformArg3
|
||||
) {
|
||||
return false; // transforms don't match
|
||||
}
|
||||
return true;
|
||||
@ -305,11 +352,12 @@ var QueueOptimizer = (function QueueOptimizerClosure() {
|
||||
}
|
||||
throw new Error(`iterateImageGroup - invalid pos: ${pos}`);
|
||||
},
|
||||
function (context, i) {
|
||||
function(context, i) {
|
||||
var MIN_IMAGES_IN_BLOCK = 3;
|
||||
var MAX_IMAGES_IN_BLOCK = 1000;
|
||||
|
||||
var fnArray = context.fnArray, argsArray = context.argsArray;
|
||||
var fnArray = context.fnArray,
|
||||
argsArray = context.argsArray;
|
||||
var curr = context.iCurr;
|
||||
var iFirstSave = curr - 3;
|
||||
var iFirstTransform = curr - 2;
|
||||
@ -320,10 +368,12 @@ var QueueOptimizer = (function QueueOptimizerClosure() {
|
||||
|
||||
// At this point, i is the index of the first op past the last valid
|
||||
// quartet.
|
||||
var count = Math.min(Math.floor((i - iFirstSave) / 4),
|
||||
MAX_IMAGES_IN_BLOCK);
|
||||
var count = Math.min(
|
||||
Math.floor((i - iFirstSave) / 4),
|
||||
MAX_IMAGES_IN_BLOCK
|
||||
);
|
||||
if (count < MIN_IMAGES_IN_BLOCK) {
|
||||
return i - (i - iFirstSave) % 4;
|
||||
return i - ((i - iFirstSave) % 4);
|
||||
}
|
||||
|
||||
// Extract the (x,y) positions from all of the matching transforms.
|
||||
@ -331,27 +381,34 @@ var QueueOptimizer = (function QueueOptimizerClosure() {
|
||||
var iTransform = iFirstTransform;
|
||||
for (var q = 0; q < count; q++, iTransform += 4) {
|
||||
var transformArgs = argsArray[iTransform];
|
||||
positions[(q << 1)] = transformArgs[4];
|
||||
positions[q << 1] = transformArgs[4];
|
||||
positions[(q << 1) + 1] = transformArgs[5];
|
||||
}
|
||||
|
||||
// Replace queue items.
|
||||
var args = [firstPIXOArg0, firstTransformArg0, firstTransformArg3,
|
||||
positions];
|
||||
var args = [
|
||||
firstPIXOArg0,
|
||||
firstTransformArg0,
|
||||
firstTransformArg3,
|
||||
positions,
|
||||
];
|
||||
fnArray.splice(iFirstSave, count * 4, OPS.paintImageXObjectRepeat);
|
||||
argsArray.splice(iFirstSave, count * 4, args);
|
||||
|
||||
return iFirstSave + 1;
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
// This replaces (beginText, setFont, setTextMatrix, showText, endText)+
|
||||
// sequences with (beginText, setFont, (setTextMatrix, showText)+, endText)+
|
||||
// sequences, if the font for each one is the same.
|
||||
addState(InitialState,
|
||||
addState(
|
||||
InitialState,
|
||||
[OPS.beginText, OPS.setFont, OPS.setTextMatrix, OPS.showText, OPS.endText],
|
||||
null,
|
||||
function iterateShowTextGroup(context, i) {
|
||||
var fnArray = context.fnArray, argsArray = context.argsArray;
|
||||
var fnArray = context.fnArray,
|
||||
argsArray = context.argsArray;
|
||||
var iFirstSave = context.iCurr - 4;
|
||||
var pos = (i - iFirstSave) % 5;
|
||||
switch (pos) {
|
||||
@ -368,8 +425,10 @@ var QueueOptimizer = (function QueueOptimizerClosure() {
|
||||
var iFirstSetFont = context.iCurr - 3;
|
||||
var firstSetFontArg0 = argsArray[iFirstSetFont][0];
|
||||
var firstSetFontArg1 = argsArray[iFirstSetFont][1];
|
||||
if (argsArray[i][0] !== firstSetFontArg0 ||
|
||||
argsArray[i][1] !== firstSetFontArg1) {
|
||||
if (
|
||||
argsArray[i][0] !== firstSetFontArg0 ||
|
||||
argsArray[i][1] !== firstSetFontArg1
|
||||
) {
|
||||
return false; // fonts don't match
|
||||
}
|
||||
return true;
|
||||
@ -378,11 +437,12 @@ var QueueOptimizer = (function QueueOptimizerClosure() {
|
||||
}
|
||||
throw new Error(`iterateShowTextGroup - invalid pos: ${pos}`);
|
||||
},
|
||||
function (context, i) {
|
||||
function(context, i) {
|
||||
var MIN_CHARS_IN_BLOCK = 3;
|
||||
var MAX_CHARS_IN_BLOCK = 1000;
|
||||
|
||||
var fnArray = context.fnArray, argsArray = context.argsArray;
|
||||
var fnArray = context.fnArray,
|
||||
argsArray = context.argsArray;
|
||||
var curr = context.iCurr;
|
||||
var iFirstBeginText = curr - 4;
|
||||
var iFirstSetFont = curr - 3;
|
||||
@ -394,23 +454,27 @@ var QueueOptimizer = (function QueueOptimizerClosure() {
|
||||
|
||||
// At this point, i is the index of the first op past the last valid
|
||||
// quintet.
|
||||
var count = Math.min(Math.floor((i - iFirstBeginText) / 5),
|
||||
MAX_CHARS_IN_BLOCK);
|
||||
var count = Math.min(
|
||||
Math.floor((i - iFirstBeginText) / 5),
|
||||
MAX_CHARS_IN_BLOCK
|
||||
);
|
||||
if (count < MIN_CHARS_IN_BLOCK) {
|
||||
return i - (i - iFirstBeginText) % 5;
|
||||
return i - ((i - iFirstBeginText) % 5);
|
||||
}
|
||||
|
||||
// If the preceding quintet is (<something>, setFont, setTextMatrix,
|
||||
// showText, endText), include that as well. (E.g. <something> might be
|
||||
// |dependency|.)
|
||||
var iFirst = iFirstBeginText;
|
||||
if (iFirstBeginText >= 4 &&
|
||||
fnArray[iFirstBeginText - 4] === fnArray[iFirstSetFont] &&
|
||||
fnArray[iFirstBeginText - 3] === fnArray[iFirstSetTextMatrix] &&
|
||||
fnArray[iFirstBeginText - 2] === fnArray[iFirstShowText] &&
|
||||
fnArray[iFirstBeginText - 1] === fnArray[iFirstEndText] &&
|
||||
argsArray[iFirstBeginText - 4][0] === firstSetFontArg0 &&
|
||||
argsArray[iFirstBeginText - 4][1] === firstSetFontArg1) {
|
||||
if (
|
||||
iFirstBeginText >= 4 &&
|
||||
fnArray[iFirstBeginText - 4] === fnArray[iFirstSetFont] &&
|
||||
fnArray[iFirstBeginText - 3] === fnArray[iFirstSetTextMatrix] &&
|
||||
fnArray[iFirstBeginText - 2] === fnArray[iFirstShowText] &&
|
||||
fnArray[iFirstBeginText - 1] === fnArray[iFirstEndText] &&
|
||||
argsArray[iFirstBeginText - 4][0] === firstSetFontArg0 &&
|
||||
argsArray[iFirstBeginText - 4][1] === firstSetFontArg1
|
||||
) {
|
||||
count++;
|
||||
iFirst -= 5;
|
||||
}
|
||||
@ -424,7 +488,8 @@ var QueueOptimizer = (function QueueOptimizerClosure() {
|
||||
}
|
||||
|
||||
return iEndText + 1;
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
function QueueOptimizer(queue) {
|
||||
this.queue = queue;
|
||||
@ -442,10 +507,11 @@ var QueueOptimizer = (function QueueOptimizerClosure() {
|
||||
_optimize() {
|
||||
// Process new fnArray item(s) chunk.
|
||||
const fnArray = this.queue.fnArray;
|
||||
let i = this.lastProcessed, ii = fnArray.length;
|
||||
let i = this.lastProcessed,
|
||||
ii = fnArray.length;
|
||||
let state = this.state;
|
||||
let match = this.match;
|
||||
if (!state && !match && (i + 1 === ii) && !InitialState[fnArray[i]]) {
|
||||
if (!state && !match && i + 1 === ii && !InitialState[fnArray[i]]) {
|
||||
// Micro-optimization for the common case: last item is not
|
||||
// optimizable, just skipping it.
|
||||
this.lastProcessed = ii;
|
||||
@ -529,9 +595,9 @@ var NullOptimizer = (function NullOptimizerClosure() {
|
||||
this.queue.argsArray.push(args);
|
||||
},
|
||||
|
||||
flush() { },
|
||||
flush() {},
|
||||
|
||||
reset() { },
|
||||
reset() {},
|
||||
};
|
||||
|
||||
return NullOptimizer;
|
||||
@ -545,7 +611,7 @@ var OperatorList = (function OperatorListClosure() {
|
||||
this._streamSink = streamSink;
|
||||
this.fnArray = [];
|
||||
this.argsArray = [];
|
||||
if (streamSink && intent !== 'oplist') {
|
||||
if (streamSink && intent !== "oplist") {
|
||||
this.optimizer = new QueueOptimizer(this);
|
||||
} else {
|
||||
this.optimizer = new NullOptimizer(this);
|
||||
@ -572,7 +638,7 @@ var OperatorList = (function OperatorListClosure() {
|
||||
* `this.length === 0` after flushing.
|
||||
*/
|
||||
get totalLength() {
|
||||
return (this._totalLength + this.length);
|
||||
return this._totalLength + this.length;
|
||||
},
|
||||
|
||||
addOp(fn, args) {
|
||||
@ -581,8 +647,10 @@ var OperatorList = (function OperatorListClosure() {
|
||||
if (this._streamSink) {
|
||||
if (this.weight >= CHUNK_SIZE) {
|
||||
this.flush();
|
||||
} else if (this.weight >= CHUNK_SIZE_ABOUT &&
|
||||
(fn === OPS.restore || fn === OPS.endText)) {
|
||||
} else if (
|
||||
this.weight >= CHUNK_SIZE_ABOUT &&
|
||||
(fn === OPS.restore || fn === OPS.endText)
|
||||
) {
|
||||
// heuristic to flush on boundary of restore or endText
|
||||
this.flush();
|
||||
}
|
||||
@ -620,7 +688,7 @@ var OperatorList = (function OperatorListClosure() {
|
||||
|
||||
get _transfers() {
|
||||
const transfers = [];
|
||||
const { fnArray, argsArray, length, } = this;
|
||||
const { fnArray, argsArray, length } = this;
|
||||
for (let i = 0; i < length; i++) {
|
||||
switch (fnArray[i]) {
|
||||
case OPS.paintInlineImageXObject:
|
||||
@ -628,10 +696,14 @@ var OperatorList = (function OperatorListClosure() {
|
||||
case OPS.paintImageMaskXObject:
|
||||
const arg = argsArray[i][0]; // first param in imgData
|
||||
|
||||
if (typeof PDFJSDev === 'undefined' ||
|
||||
PDFJSDev.test('!PRODUCTION || TESTING')) {
|
||||
assert(arg.data instanceof Uint8ClampedArray,
|
||||
'OperatorList._transfers: Unsupported "arg.data" type.');
|
||||
if (
|
||||
typeof PDFJSDev === "undefined" ||
|
||||
PDFJSDev.test("!PRODUCTION || TESTING")
|
||||
) {
|
||||
assert(
|
||||
arg.data instanceof Uint8ClampedArray,
|
||||
'OperatorList._transfers: Unsupported "arg.data" type.'
|
||||
);
|
||||
}
|
||||
if (!arg.cached) {
|
||||
transfers.push(arg.data.buffer);
|
||||
@ -647,12 +719,16 @@ var OperatorList = (function OperatorListClosure() {
|
||||
const length = this.length;
|
||||
this._totalLength += length;
|
||||
|
||||
this._streamSink.enqueue({
|
||||
fnArray: this.fnArray,
|
||||
argsArray: this.argsArray,
|
||||
lastChunk,
|
||||
length,
|
||||
}, 1, this._transfers);
|
||||
this._streamSink.enqueue(
|
||||
{
|
||||
fnArray: this.fnArray,
|
||||
argsArray: this.argsArray,
|
||||
lastChunk,
|
||||
length,
|
||||
},
|
||||
1,
|
||||
this._transfers
|
||||
);
|
||||
|
||||
this.dependencies = Object.create(null);
|
||||
this.fnArray.length = 0;
|
||||
@ -665,6 +741,4 @@ var OperatorList = (function OperatorListClosure() {
|
||||
return OperatorList;
|
||||
})();
|
||||
|
||||
export {
|
||||
OperatorList,
|
||||
};
|
||||
export { OperatorList };
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -12,14 +12,19 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/* eslint-disable no-multi-spaces */
|
||||
|
||||
import {
|
||||
assert, FormatError, info, unreachable, UNSUPPORTED_FEATURES, Util, warn
|
||||
} from '../shared/util';
|
||||
import { ColorSpace } from './colorspace';
|
||||
import { isStream } from './primitives';
|
||||
import { MissingDataException } from './core_utils';
|
||||
assert,
|
||||
FormatError,
|
||||
info,
|
||||
unreachable,
|
||||
UNSUPPORTED_FEATURES,
|
||||
Util,
|
||||
warn,
|
||||
} from "../shared/util";
|
||||
import { ColorSpace } from "./colorspace";
|
||||
import { isStream } from "./primitives";
|
||||
import { MissingDataException } from "./core_utils";
|
||||
|
||||
var ShadingType = {
|
||||
FUNCTION_BASED: 1,
|
||||
@ -34,7 +39,7 @@ var ShadingType = {
|
||||
var Pattern = (function PatternClosure() {
|
||||
// Constructor should define this.getPattern
|
||||
function Pattern() {
|
||||
unreachable('should not call Pattern constructor');
|
||||
unreachable("should not call Pattern constructor");
|
||||
}
|
||||
|
||||
Pattern.prototype = {
|
||||
@ -45,33 +50,50 @@ var Pattern = (function PatternClosure() {
|
||||
},
|
||||
};
|
||||
|
||||
Pattern.parseShading = function(shading, matrix, xref, res, handler,
|
||||
pdfFunctionFactory) {
|
||||
Pattern.parseShading = function(
|
||||
shading,
|
||||
matrix,
|
||||
xref,
|
||||
res,
|
||||
handler,
|
||||
pdfFunctionFactory
|
||||
) {
|
||||
var dict = isStream(shading) ? shading.dict : shading;
|
||||
var type = dict.get('ShadingType');
|
||||
var type = dict.get("ShadingType");
|
||||
|
||||
try {
|
||||
switch (type) {
|
||||
case ShadingType.AXIAL:
|
||||
case ShadingType.RADIAL:
|
||||
// Both radial and axial shadings are handled by RadialAxial shading.
|
||||
return new Shadings.RadialAxial(dict, matrix, xref, res,
|
||||
pdfFunctionFactory);
|
||||
return new Shadings.RadialAxial(
|
||||
dict,
|
||||
matrix,
|
||||
xref,
|
||||
res,
|
||||
pdfFunctionFactory
|
||||
);
|
||||
case ShadingType.FREE_FORM_MESH:
|
||||
case ShadingType.LATTICE_FORM_MESH:
|
||||
case ShadingType.COONS_PATCH_MESH:
|
||||
case ShadingType.TENSOR_PATCH_MESH:
|
||||
return new Shadings.Mesh(shading, matrix, xref, res,
|
||||
pdfFunctionFactory);
|
||||
return new Shadings.Mesh(
|
||||
shading,
|
||||
matrix,
|
||||
xref,
|
||||
res,
|
||||
pdfFunctionFactory
|
||||
);
|
||||
default:
|
||||
throw new FormatError('Unsupported ShadingType: ' + type);
|
||||
throw new FormatError("Unsupported ShadingType: " + type);
|
||||
}
|
||||
} catch (ex) {
|
||||
if (ex instanceof MissingDataException) {
|
||||
throw ex;
|
||||
}
|
||||
handler.send('UnsupportedFeature',
|
||||
{ featureId: UNSUPPORTED_FEATURES.shadingPattern, });
|
||||
handler.send("UnsupportedFeature", {
|
||||
featureId: UNSUPPORTED_FEATURES.shadingPattern,
|
||||
});
|
||||
warn(ex);
|
||||
return new Shadings.Dummy();
|
||||
}
|
||||
@ -90,35 +112,39 @@ Shadings.SMALL_NUMBER = 1e-6;
|
||||
Shadings.RadialAxial = (function RadialAxialClosure() {
|
||||
function RadialAxial(dict, matrix, xref, res, pdfFunctionFactory) {
|
||||
this.matrix = matrix;
|
||||
this.coordsArr = dict.getArray('Coords');
|
||||
this.shadingType = dict.get('ShadingType');
|
||||
this.type = 'Pattern';
|
||||
var cs = dict.get('ColorSpace', 'CS');
|
||||
this.coordsArr = dict.getArray("Coords");
|
||||
this.shadingType = dict.get("ShadingType");
|
||||
this.type = "Pattern";
|
||||
var cs = dict.get("ColorSpace", "CS");
|
||||
cs = ColorSpace.parse(cs, xref, res, pdfFunctionFactory);
|
||||
this.cs = cs;
|
||||
const bbox = dict.getArray('BBox');
|
||||
const bbox = dict.getArray("BBox");
|
||||
if (Array.isArray(bbox) && bbox.length === 4) {
|
||||
this.bbox = Util.normalizeRect(bbox);
|
||||
} else {
|
||||
this.bbox = null;
|
||||
}
|
||||
|
||||
var t0 = 0.0, t1 = 1.0;
|
||||
if (dict.has('Domain')) {
|
||||
var domainArr = dict.getArray('Domain');
|
||||
var t0 = 0.0,
|
||||
t1 = 1.0;
|
||||
if (dict.has("Domain")) {
|
||||
var domainArr = dict.getArray("Domain");
|
||||
t0 = domainArr[0];
|
||||
t1 = domainArr[1];
|
||||
}
|
||||
|
||||
var extendStart = false, extendEnd = false;
|
||||
if (dict.has('Extend')) {
|
||||
var extendArr = dict.getArray('Extend');
|
||||
var extendStart = false,
|
||||
extendEnd = false;
|
||||
if (dict.has("Extend")) {
|
||||
var extendArr = dict.getArray("Extend");
|
||||
extendStart = extendArr[0];
|
||||
extendEnd = extendArr[1];
|
||||
}
|
||||
|
||||
if (this.shadingType === ShadingType.RADIAL &&
|
||||
(!extendStart || !extendEnd)) {
|
||||
if (
|
||||
this.shadingType === ShadingType.RADIAL &&
|
||||
(!extendStart || !extendEnd)
|
||||
) {
|
||||
// Radial gradient only currently works if either circle is fully within
|
||||
// the other circle.
|
||||
var x1 = this.coordsArr[0];
|
||||
@ -128,16 +154,15 @@ Shadings.RadialAxial = (function RadialAxialClosure() {
|
||||
var y2 = this.coordsArr[4];
|
||||
var r2 = this.coordsArr[5];
|
||||
var distance = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
|
||||
if (r1 <= r2 + distance &&
|
||||
r2 <= r1 + distance) {
|
||||
warn('Unsupported radial gradient.');
|
||||
if (r1 <= r2 + distance && r2 <= r1 + distance) {
|
||||
warn("Unsupported radial gradient.");
|
||||
}
|
||||
}
|
||||
|
||||
this.extendStart = extendStart;
|
||||
this.extendEnd = extendEnd;
|
||||
|
||||
var fnObj = dict.get('Function');
|
||||
var fnObj = dict.get("Function");
|
||||
var fn = pdfFunctionFactory.createFromArray(fnObj);
|
||||
|
||||
// 10 samples seems good enough for now, but probably won't work
|
||||
@ -146,17 +171,18 @@ Shadings.RadialAxial = (function RadialAxialClosure() {
|
||||
const NUMBER_OF_SAMPLES = 10;
|
||||
const step = (t1 - t0) / NUMBER_OF_SAMPLES;
|
||||
|
||||
var colorStops = this.colorStops = [];
|
||||
var colorStops = (this.colorStops = []);
|
||||
|
||||
// Protect against bad domains.
|
||||
if (t0 >= t1 || step <= 0) {
|
||||
// Acrobat doesn't seem to handle these cases so we'll ignore for
|
||||
// now.
|
||||
info('Bad shading domain.');
|
||||
info("Bad shading domain.");
|
||||
return;
|
||||
}
|
||||
|
||||
var color = new Float32Array(cs.numComps), ratio = new Float32Array(1);
|
||||
var color = new Float32Array(cs.numComps),
|
||||
ratio = new Float32Array(1);
|
||||
var rgbColor;
|
||||
for (let i = 0; i <= NUMBER_OF_SAMPLES; i++) {
|
||||
ratio[0] = t0 + i * step;
|
||||
@ -166,9 +192,9 @@ Shadings.RadialAxial = (function RadialAxialClosure() {
|
||||
colorStops.push([i / NUMBER_OF_SAMPLES, cssColor]);
|
||||
}
|
||||
|
||||
var background = 'transparent';
|
||||
if (dict.has('Background')) {
|
||||
rgbColor = cs.getRgb(dict.get('Background'), 0);
|
||||
var background = "transparent";
|
||||
if (dict.has("Background")) {
|
||||
rgbColor = cs.getRgb(dict.get("Background"), 0);
|
||||
background = Util.makeCssRgb(rgbColor[0], rgbColor[1], rgbColor[2]);
|
||||
}
|
||||
|
||||
@ -197,13 +223,13 @@ Shadings.RadialAxial = (function RadialAxialClosure() {
|
||||
p1 = [coordsArr[2], coordsArr[3]];
|
||||
r0 = null;
|
||||
r1 = null;
|
||||
type = 'axial';
|
||||
type = "axial";
|
||||
} else if (shadingType === ShadingType.RADIAL) {
|
||||
p0 = [coordsArr[0], coordsArr[1]];
|
||||
p1 = [coordsArr[3], coordsArr[4]];
|
||||
r0 = coordsArr[2];
|
||||
r1 = coordsArr[5];
|
||||
type = 'radial';
|
||||
type = "radial";
|
||||
} else {
|
||||
unreachable(`getPattern type unknown: ${shadingType}`);
|
||||
}
|
||||
@ -219,7 +245,7 @@ Shadings.RadialAxial = (function RadialAxialClosure() {
|
||||
}
|
||||
}
|
||||
|
||||
return ['RadialAxial', type, this.bbox, this.colorStops, p0, p1, r0, r1];
|
||||
return ["RadialAxial", type, this.bbox, this.colorStops, p0, p1, r0, r1];
|
||||
},
|
||||
};
|
||||
|
||||
@ -238,8 +264,9 @@ Shadings.Mesh = (function MeshClosure() {
|
||||
var numComps = context.numComps;
|
||||
this.tmpCompsBuf = new Float32Array(numComps);
|
||||
var csNumComps = context.colorSpace.numComps;
|
||||
this.tmpCsCompsBuf = context.colorFn ? new Float32Array(csNumComps) :
|
||||
this.tmpCompsBuf;
|
||||
this.tmpCsCompsBuf = context.colorFn
|
||||
? new Float32Array(csNumComps)
|
||||
: this.tmpCompsBuf;
|
||||
}
|
||||
MeshStreamReader.prototype = {
|
||||
get hasData() {
|
||||
@ -262,16 +289,26 @@ Shadings.Mesh = (function MeshClosure() {
|
||||
var bufferLength = this.bufferLength;
|
||||
if (n === 32) {
|
||||
if (bufferLength === 0) {
|
||||
return ((this.stream.getByte() << 24) |
|
||||
(this.stream.getByte() << 16) | (this.stream.getByte() << 8) |
|
||||
this.stream.getByte()) >>> 0;
|
||||
return (
|
||||
((this.stream.getByte() << 24) |
|
||||
(this.stream.getByte() << 16) |
|
||||
(this.stream.getByte() << 8) |
|
||||
this.stream.getByte()) >>>
|
||||
0
|
||||
);
|
||||
}
|
||||
buffer = (buffer << 24) | (this.stream.getByte() << 16) |
|
||||
(this.stream.getByte() << 8) | this.stream.getByte();
|
||||
buffer =
|
||||
(buffer << 24) |
|
||||
(this.stream.getByte() << 16) |
|
||||
(this.stream.getByte() << 8) |
|
||||
this.stream.getByte();
|
||||
var nextByte = this.stream.getByte();
|
||||
this.buffer = nextByte & ((1 << bufferLength) - 1);
|
||||
return ((buffer << (8 - bufferLength)) |
|
||||
((nextByte & 0xFF) >> bufferLength)) >>> 0;
|
||||
return (
|
||||
((buffer << (8 - bufferLength)) |
|
||||
((nextByte & 0xff) >> bufferLength)) >>>
|
||||
0
|
||||
);
|
||||
}
|
||||
if (n === 8 && bufferLength === 0) {
|
||||
return this.stream.getByte();
|
||||
@ -297,18 +334,22 @@ Shadings.Mesh = (function MeshClosure() {
|
||||
var xi = this.readBits(bitsPerCoordinate);
|
||||
var yi = this.readBits(bitsPerCoordinate);
|
||||
var decode = this.context.decode;
|
||||
var scale = bitsPerCoordinate < 32 ? 1 / ((1 << bitsPerCoordinate) - 1) :
|
||||
2.3283064365386963e-10; // 2 ^ -32
|
||||
var scale =
|
||||
bitsPerCoordinate < 32
|
||||
? 1 / ((1 << bitsPerCoordinate) - 1)
|
||||
: 2.3283064365386963e-10; // 2 ^ -32
|
||||
return [
|
||||
xi * scale * (decode[1] - decode[0]) + decode[0],
|
||||
yi * scale * (decode[3] - decode[2]) + decode[2]
|
||||
yi * scale * (decode[3] - decode[2]) + decode[2],
|
||||
];
|
||||
},
|
||||
readComponents: function MeshStreamReader_readComponents() {
|
||||
var numComps = this.context.numComps;
|
||||
var bitsPerComponent = this.context.bitsPerComponent;
|
||||
var scale = bitsPerComponent < 32 ? 1 / ((1 << bitsPerComponent) - 1) :
|
||||
2.3283064365386963e-10; // 2 ^ -32
|
||||
var scale =
|
||||
bitsPerComponent < 32
|
||||
? 1 / ((1 << bitsPerComponent) - 1)
|
||||
: 2.3283064365386963e-10; // 2 ^ -32
|
||||
var decode = this.context.decode;
|
||||
var components = this.tmpCompsBuf;
|
||||
for (var i = 0, j = 4; i < numComps; i++, j += 2) {
|
||||
@ -333,9 +374,10 @@ Shadings.Mesh = (function MeshClosure() {
|
||||
var f = reader.readFlag();
|
||||
var coord = reader.readCoordinate();
|
||||
var color = reader.readComponents();
|
||||
if (verticesLeft === 0) { // ignoring flags if we started a triangle
|
||||
if (verticesLeft === 0) {
|
||||
// ignoring flags if we started a triangle
|
||||
if (!(0 <= f && f <= 2)) {
|
||||
throw new FormatError('Unknown type4 flag');
|
||||
throw new FormatError("Unknown type4 flag");
|
||||
}
|
||||
switch (f) {
|
||||
case 0:
|
||||
@ -360,7 +402,7 @@ Shadings.Mesh = (function MeshClosure() {
|
||||
reader.align();
|
||||
}
|
||||
mesh.figures.push({
|
||||
type: 'triangles',
|
||||
type: "triangles",
|
||||
coords: new Int32Array(ps),
|
||||
colors: new Int32Array(ps),
|
||||
});
|
||||
@ -378,7 +420,7 @@ Shadings.Mesh = (function MeshClosure() {
|
||||
colors.push(color);
|
||||
}
|
||||
mesh.figures.push({
|
||||
type: 'lattice',
|
||||
type: "lattice",
|
||||
coords: new Int32Array(ps),
|
||||
colors: new Int32Array(ps),
|
||||
verticesPerRow,
|
||||
@ -394,9 +436,16 @@ Shadings.Mesh = (function MeshClosure() {
|
||||
function buildB(count) {
|
||||
var lut = [];
|
||||
for (var i = 0; i <= count; i++) {
|
||||
var t = i / count, t_ = 1 - t;
|
||||
lut.push(new Float32Array([t_ * t_ * t_, 3 * t * t_ * t_,
|
||||
3 * t * t * t_, t * t * t]));
|
||||
var t = i / count,
|
||||
t_ = 1 - t;
|
||||
lut.push(
|
||||
new Float32Array([
|
||||
t_ * t_ * t_,
|
||||
3 * t * t_ * t_,
|
||||
3 * t * t * t_,
|
||||
t * t * t,
|
||||
])
|
||||
);
|
||||
}
|
||||
return lut;
|
||||
}
|
||||
@ -411,37 +460,66 @@ Shadings.Mesh = (function MeshClosure() {
|
||||
|
||||
function buildFigureFromPatch(mesh, index) {
|
||||
var figure = mesh.figures[index];
|
||||
assert(figure.type === 'patch', 'Unexpected patch mesh figure');
|
||||
assert(figure.type === "patch", "Unexpected patch mesh figure");
|
||||
|
||||
var coords = mesh.coords, colors = mesh.colors;
|
||||
var coords = mesh.coords,
|
||||
colors = mesh.colors;
|
||||
var pi = figure.coords;
|
||||
var ci = figure.colors;
|
||||
|
||||
var figureMinX = Math.min(coords[pi[0]][0], coords[pi[3]][0],
|
||||
coords[pi[12]][0], coords[pi[15]][0]);
|
||||
var figureMinY = Math.min(coords[pi[0]][1], coords[pi[3]][1],
|
||||
coords[pi[12]][1], coords[pi[15]][1]);
|
||||
var figureMaxX = Math.max(coords[pi[0]][0], coords[pi[3]][0],
|
||||
coords[pi[12]][0], coords[pi[15]][0]);
|
||||
var figureMaxY = Math.max(coords[pi[0]][1], coords[pi[3]][1],
|
||||
coords[pi[12]][1], coords[pi[15]][1]);
|
||||
var splitXBy = Math.ceil((figureMaxX - figureMinX) * TRIANGLE_DENSITY /
|
||||
(mesh.bounds[2] - mesh.bounds[0]));
|
||||
splitXBy = Math.max(MIN_SPLIT_PATCH_CHUNKS_AMOUNT,
|
||||
Math.min(MAX_SPLIT_PATCH_CHUNKS_AMOUNT, splitXBy));
|
||||
var splitYBy = Math.ceil((figureMaxY - figureMinY) * TRIANGLE_DENSITY /
|
||||
(mesh.bounds[3] - mesh.bounds[1]));
|
||||
splitYBy = Math.max(MIN_SPLIT_PATCH_CHUNKS_AMOUNT,
|
||||
Math.min(MAX_SPLIT_PATCH_CHUNKS_AMOUNT, splitYBy));
|
||||
var figureMinX = Math.min(
|
||||
coords[pi[0]][0],
|
||||
coords[pi[3]][0],
|
||||
coords[pi[12]][0],
|
||||
coords[pi[15]][0]
|
||||
);
|
||||
var figureMinY = Math.min(
|
||||
coords[pi[0]][1],
|
||||
coords[pi[3]][1],
|
||||
coords[pi[12]][1],
|
||||
coords[pi[15]][1]
|
||||
);
|
||||
var figureMaxX = Math.max(
|
||||
coords[pi[0]][0],
|
||||
coords[pi[3]][0],
|
||||
coords[pi[12]][0],
|
||||
coords[pi[15]][0]
|
||||
);
|
||||
var figureMaxY = Math.max(
|
||||
coords[pi[0]][1],
|
||||
coords[pi[3]][1],
|
||||
coords[pi[12]][1],
|
||||
coords[pi[15]][1]
|
||||
);
|
||||
var splitXBy = Math.ceil(
|
||||
((figureMaxX - figureMinX) * TRIANGLE_DENSITY) /
|
||||
(mesh.bounds[2] - mesh.bounds[0])
|
||||
);
|
||||
splitXBy = Math.max(
|
||||
MIN_SPLIT_PATCH_CHUNKS_AMOUNT,
|
||||
Math.min(MAX_SPLIT_PATCH_CHUNKS_AMOUNT, splitXBy)
|
||||
);
|
||||
var splitYBy = Math.ceil(
|
||||
((figureMaxY - figureMinY) * TRIANGLE_DENSITY) /
|
||||
(mesh.bounds[3] - mesh.bounds[1])
|
||||
);
|
||||
splitYBy = Math.max(
|
||||
MIN_SPLIT_PATCH_CHUNKS_AMOUNT,
|
||||
Math.min(MAX_SPLIT_PATCH_CHUNKS_AMOUNT, splitYBy)
|
||||
);
|
||||
|
||||
var verticesPerRow = splitXBy + 1;
|
||||
var figureCoords = new Int32Array((splitYBy + 1) * verticesPerRow);
|
||||
var figureColors = new Int32Array((splitYBy + 1) * verticesPerRow);
|
||||
var k = 0;
|
||||
var cl = new Uint8Array(3), cr = new Uint8Array(3);
|
||||
var c0 = colors[ci[0]], c1 = colors[ci[1]],
|
||||
c2 = colors[ci[2]], c3 = colors[ci[3]];
|
||||
var bRow = getB(splitYBy), bCol = getB(splitXBy);
|
||||
var cl = new Uint8Array(3),
|
||||
cr = new Uint8Array(3);
|
||||
var c0 = colors[ci[0]],
|
||||
c1 = colors[ci[1]],
|
||||
c2 = colors[ci[2]],
|
||||
c3 = colors[ci[3]];
|
||||
var bRow = getB(splitYBy),
|
||||
bCol = getB(splitXBy);
|
||||
for (var row = 0; row <= splitYBy; row++) {
|
||||
cl[0] = ((c0[0] * (splitYBy - row) + c2[0] * row) / splitYBy) | 0;
|
||||
cl[1] = ((c0[1] * (splitYBy - row) + c2[1] * row) / splitYBy) | 0;
|
||||
@ -452,11 +530,14 @@ Shadings.Mesh = (function MeshClosure() {
|
||||
cr[2] = ((c1[2] * (splitYBy - row) + c3[2] * row) / splitYBy) | 0;
|
||||
|
||||
for (var col = 0; col <= splitXBy; col++, k++) {
|
||||
if ((row === 0 || row === splitYBy) &&
|
||||
(col === 0 || col === splitXBy)) {
|
||||
if (
|
||||
(row === 0 || row === splitYBy) &&
|
||||
(col === 0 || col === splitXBy)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
var x = 0, y = 0;
|
||||
var x = 0,
|
||||
y = 0;
|
||||
var q = 0;
|
||||
for (var i = 0; i <= 3; i++) {
|
||||
for (var j = 0; j <= 3; j++, q++) {
|
||||
@ -485,7 +566,7 @@ Shadings.Mesh = (function MeshClosure() {
|
||||
figureColors[verticesPerRow * splitYBy + splitXBy] = ci[3];
|
||||
|
||||
mesh.figures[index] = {
|
||||
type: 'lattice',
|
||||
type: "lattice",
|
||||
coords: figureCoords,
|
||||
colors: figureColors,
|
||||
verticesPerRow,
|
||||
@ -501,19 +582,20 @@ Shadings.Mesh = (function MeshClosure() {
|
||||
while (reader.hasData) {
|
||||
var f = reader.readFlag();
|
||||
if (!(0 <= f && f <= 3)) {
|
||||
throw new FormatError('Unknown type6 flag');
|
||||
throw new FormatError("Unknown type6 flag");
|
||||
}
|
||||
var i, ii;
|
||||
var pi = coords.length;
|
||||
for (i = 0, ii = (f !== 0 ? 8 : 12); i < ii; i++) {
|
||||
for (i = 0, ii = f !== 0 ? 8 : 12; i < ii; i++) {
|
||||
coords.push(reader.readCoordinate());
|
||||
}
|
||||
var ci = colors.length;
|
||||
for (i = 0, ii = (f !== 0 ? 2 : 4); i < ii; i++) {
|
||||
for (i = 0, ii = f !== 0 ? 2 : 4; i < ii; i++) {
|
||||
colors.push(reader.readComponents());
|
||||
}
|
||||
var tmp1, tmp2, tmp3, tmp4;
|
||||
switch (f) {
|
||||
// prettier-ignore
|
||||
case 0:
|
||||
ps[12] = pi + 3; ps[13] = pi + 4; ps[14] = pi + 5; ps[15] = pi + 6;
|
||||
ps[ 8] = pi + 2; /* values for 5, 6, 9, 10 are */ ps[11] = pi + 7;
|
||||
@ -522,6 +604,7 @@ Shadings.Mesh = (function MeshClosure() {
|
||||
cs[2] = ci + 1; cs[3] = ci + 2;
|
||||
cs[0] = ci; cs[1] = ci + 3;
|
||||
break;
|
||||
// prettier-ignore
|
||||
case 1:
|
||||
tmp1 = ps[12]; tmp2 = ps[13]; tmp3 = ps[14]; tmp4 = ps[15];
|
||||
ps[12] = tmp4; ps[13] = pi + 0; ps[14] = pi + 1; ps[15] = pi + 2;
|
||||
@ -532,6 +615,7 @@ Shadings.Mesh = (function MeshClosure() {
|
||||
cs[2] = tmp2; cs[3] = ci;
|
||||
cs[0] = tmp1; cs[1] = ci + 1;
|
||||
break;
|
||||
// prettier-ignore
|
||||
case 2:
|
||||
tmp1 = ps[15];
|
||||
tmp2 = ps[11];
|
||||
@ -543,6 +627,7 @@ Shadings.Mesh = (function MeshClosure() {
|
||||
cs[2] = cs[1]; cs[3] = ci;
|
||||
cs[0] = tmp1; cs[1] = ci + 1;
|
||||
break;
|
||||
// prettier-ignore
|
||||
case 3:
|
||||
ps[12] = ps[0]; ps[13] = pi + 0; ps[14] = pi + 1; ps[15] = pi + 2;
|
||||
ps[ 8] = ps[1]; /* values for 5, 6, 9, 10 are */ ps[11] = pi + 3;
|
||||
@ -555,50 +640,66 @@ Shadings.Mesh = (function MeshClosure() {
|
||||
// set p11, p12, p21, p22
|
||||
ps[5] = coords.length;
|
||||
coords.push([
|
||||
(-4 * coords[ps[0]][0] - coords[ps[15]][0] +
|
||||
(-4 * coords[ps[0]][0] -
|
||||
coords[ps[15]][0] +
|
||||
6 * (coords[ps[4]][0] + coords[ps[1]][0]) -
|
||||
2 * (coords[ps[12]][0] + coords[ps[3]][0]) +
|
||||
3 * (coords[ps[13]][0] + coords[ps[7]][0])) / 9,
|
||||
(-4 * coords[ps[0]][1] - coords[ps[15]][1] +
|
||||
3 * (coords[ps[13]][0] + coords[ps[7]][0])) /
|
||||
9,
|
||||
(-4 * coords[ps[0]][1] -
|
||||
coords[ps[15]][1] +
|
||||
6 * (coords[ps[4]][1] + coords[ps[1]][1]) -
|
||||
2 * (coords[ps[12]][1] + coords[ps[3]][1]) +
|
||||
3 * (coords[ps[13]][1] + coords[ps[7]][1])) / 9
|
||||
3 * (coords[ps[13]][1] + coords[ps[7]][1])) /
|
||||
9,
|
||||
]);
|
||||
ps[6] = coords.length;
|
||||
coords.push([
|
||||
(-4 * coords[ps[3]][0] - coords[ps[12]][0] +
|
||||
(-4 * coords[ps[3]][0] -
|
||||
coords[ps[12]][0] +
|
||||
6 * (coords[ps[2]][0] + coords[ps[7]][0]) -
|
||||
2 * (coords[ps[0]][0] + coords[ps[15]][0]) +
|
||||
3 * (coords[ps[4]][0] + coords[ps[14]][0])) / 9,
|
||||
(-4 * coords[ps[3]][1] - coords[ps[12]][1] +
|
||||
3 * (coords[ps[4]][0] + coords[ps[14]][0])) /
|
||||
9,
|
||||
(-4 * coords[ps[3]][1] -
|
||||
coords[ps[12]][1] +
|
||||
6 * (coords[ps[2]][1] + coords[ps[7]][1]) -
|
||||
2 * (coords[ps[0]][1] + coords[ps[15]][1]) +
|
||||
3 * (coords[ps[4]][1] + coords[ps[14]][1])) / 9
|
||||
3 * (coords[ps[4]][1] + coords[ps[14]][1])) /
|
||||
9,
|
||||
]);
|
||||
ps[9] = coords.length;
|
||||
coords.push([
|
||||
(-4 * coords[ps[12]][0] - coords[ps[3]][0] +
|
||||
(-4 * coords[ps[12]][0] -
|
||||
coords[ps[3]][0] +
|
||||
6 * (coords[ps[8]][0] + coords[ps[13]][0]) -
|
||||
2 * (coords[ps[0]][0] + coords[ps[15]][0]) +
|
||||
3 * (coords[ps[11]][0] + coords[ps[1]][0])) / 9,
|
||||
(-4 * coords[ps[12]][1] - coords[ps[3]][1] +
|
||||
3 * (coords[ps[11]][0] + coords[ps[1]][0])) /
|
||||
9,
|
||||
(-4 * coords[ps[12]][1] -
|
||||
coords[ps[3]][1] +
|
||||
6 * (coords[ps[8]][1] + coords[ps[13]][1]) -
|
||||
2 * (coords[ps[0]][1] + coords[ps[15]][1]) +
|
||||
3 * (coords[ps[11]][1] + coords[ps[1]][1])) / 9
|
||||
3 * (coords[ps[11]][1] + coords[ps[1]][1])) /
|
||||
9,
|
||||
]);
|
||||
ps[10] = coords.length;
|
||||
coords.push([
|
||||
(-4 * coords[ps[15]][0] - coords[ps[0]][0] +
|
||||
(-4 * coords[ps[15]][0] -
|
||||
coords[ps[0]][0] +
|
||||
6 * (coords[ps[11]][0] + coords[ps[14]][0]) -
|
||||
2 * (coords[ps[12]][0] + coords[ps[3]][0]) +
|
||||
3 * (coords[ps[2]][0] + coords[ps[8]][0])) / 9,
|
||||
(-4 * coords[ps[15]][1] - coords[ps[0]][1] +
|
||||
3 * (coords[ps[2]][0] + coords[ps[8]][0])) /
|
||||
9,
|
||||
(-4 * coords[ps[15]][1] -
|
||||
coords[ps[0]][1] +
|
||||
6 * (coords[ps[11]][1] + coords[ps[14]][1]) -
|
||||
2 * (coords[ps[12]][1] + coords[ps[3]][1]) +
|
||||
3 * (coords[ps[2]][1] + coords[ps[8]][1])) / 9
|
||||
3 * (coords[ps[2]][1] + coords[ps[8]][1])) /
|
||||
9,
|
||||
]);
|
||||
mesh.figures.push({
|
||||
type: 'patch',
|
||||
type: "patch",
|
||||
coords: new Int32Array(ps), // making copies of ps and cs
|
||||
colors: new Int32Array(cs),
|
||||
});
|
||||
@ -613,19 +714,20 @@ Shadings.Mesh = (function MeshClosure() {
|
||||
while (reader.hasData) {
|
||||
var f = reader.readFlag();
|
||||
if (!(0 <= f && f <= 3)) {
|
||||
throw new FormatError('Unknown type7 flag');
|
||||
throw new FormatError("Unknown type7 flag");
|
||||
}
|
||||
var i, ii;
|
||||
var pi = coords.length;
|
||||
for (i = 0, ii = (f !== 0 ? 12 : 16); i < ii; i++) {
|
||||
for (i = 0, ii = f !== 0 ? 12 : 16; i < ii; i++) {
|
||||
coords.push(reader.readCoordinate());
|
||||
}
|
||||
var ci = colors.length;
|
||||
for (i = 0, ii = (f !== 0 ? 2 : 4); i < ii; i++) {
|
||||
for (i = 0, ii = f !== 0 ? 2 : 4; i < ii; i++) {
|
||||
colors.push(reader.readComponents());
|
||||
}
|
||||
var tmp1, tmp2, tmp3, tmp4;
|
||||
switch (f) {
|
||||
// prettier-ignore
|
||||
case 0:
|
||||
ps[12] = pi + 3; ps[13] = pi + 4; ps[14] = pi + 5; ps[15] = pi + 6;
|
||||
ps[ 8] = pi + 2; ps[ 9] = pi + 13; ps[10] = pi + 14; ps[11] = pi + 7;
|
||||
@ -634,6 +736,7 @@ Shadings.Mesh = (function MeshClosure() {
|
||||
cs[2] = ci + 1; cs[3] = ci + 2;
|
||||
cs[0] = ci; cs[1] = ci + 3;
|
||||
break;
|
||||
// prettier-ignore
|
||||
case 1:
|
||||
tmp1 = ps[12]; tmp2 = ps[13]; tmp3 = ps[14]; tmp4 = ps[15];
|
||||
ps[12] = tmp4; ps[13] = pi + 0; ps[14] = pi + 1; ps[15] = pi + 2;
|
||||
@ -644,6 +747,7 @@ Shadings.Mesh = (function MeshClosure() {
|
||||
cs[2] = tmp2; cs[3] = ci;
|
||||
cs[0] = tmp1; cs[1] = ci + 1;
|
||||
break;
|
||||
// prettier-ignore
|
||||
case 2:
|
||||
tmp1 = ps[15];
|
||||
tmp2 = ps[11];
|
||||
@ -655,6 +759,7 @@ Shadings.Mesh = (function MeshClosure() {
|
||||
cs[2] = cs[1]; cs[3] = ci;
|
||||
cs[0] = tmp1; cs[1] = ci + 1;
|
||||
break;
|
||||
// prettier-ignore
|
||||
case 3:
|
||||
ps[12] = ps[0]; ps[13] = pi + 0; ps[14] = pi + 1; ps[15] = pi + 2;
|
||||
ps[ 8] = ps[1]; ps[ 9] = pi + 9; ps[10] = pi + 10; ps[11] = pi + 3;
|
||||
@ -665,7 +770,7 @@ Shadings.Mesh = (function MeshClosure() {
|
||||
break;
|
||||
}
|
||||
mesh.figures.push({
|
||||
type: 'patch',
|
||||
type: "patch",
|
||||
coords: new Int32Array(ps), // making copies of ps and cs
|
||||
colors: new Int32Array(cs),
|
||||
});
|
||||
@ -673,10 +778,13 @@ Shadings.Mesh = (function MeshClosure() {
|
||||
}
|
||||
|
||||
function updateBounds(mesh) {
|
||||
var minX = mesh.coords[0][0], minY = mesh.coords[0][1],
|
||||
maxX = minX, maxY = minY;
|
||||
var minX = mesh.coords[0][0],
|
||||
minY = mesh.coords[0][1],
|
||||
maxX = minX,
|
||||
maxY = minY;
|
||||
for (var i = 1, ii = mesh.coords.length; i < ii; i++) {
|
||||
var x = mesh.coords[i][0], y = mesh.coords[i][1];
|
||||
var x = mesh.coords[i][0],
|
||||
y = mesh.coords[i][1];
|
||||
minX = minX > x ? x : minX;
|
||||
minY = minY > y ? y : minY;
|
||||
maxX = maxX < x ? x : maxX;
|
||||
@ -709,7 +817,9 @@ Shadings.Mesh = (function MeshClosure() {
|
||||
|
||||
var figures = mesh.figures;
|
||||
for (i = 0, ii = figures.length; i < ii; i++) {
|
||||
var figure = figures[i], ps = figure.coords, cs = figure.colors;
|
||||
var figure = figures[i],
|
||||
ps = figure.coords,
|
||||
cs = figure.colors;
|
||||
for (j = 0, jj = ps.length; j < jj; j++) {
|
||||
ps[j] *= 2;
|
||||
cs[j] *= 3;
|
||||
@ -719,25 +829,26 @@ Shadings.Mesh = (function MeshClosure() {
|
||||
|
||||
function Mesh(stream, matrix, xref, res, pdfFunctionFactory) {
|
||||
if (!isStream(stream)) {
|
||||
throw new FormatError('Mesh data is not a stream');
|
||||
throw new FormatError("Mesh data is not a stream");
|
||||
}
|
||||
var dict = stream.dict;
|
||||
this.matrix = matrix;
|
||||
this.shadingType = dict.get('ShadingType');
|
||||
this.type = 'Pattern';
|
||||
const bbox = dict.getArray('BBox');
|
||||
this.shadingType = dict.get("ShadingType");
|
||||
this.type = "Pattern";
|
||||
const bbox = dict.getArray("BBox");
|
||||
if (Array.isArray(bbox) && bbox.length === 4) {
|
||||
this.bbox = Util.normalizeRect(bbox);
|
||||
} else {
|
||||
this.bbox = null;
|
||||
}
|
||||
var cs = dict.get('ColorSpace', 'CS');
|
||||
var cs = dict.get("ColorSpace", "CS");
|
||||
cs = ColorSpace.parse(cs, xref, res, pdfFunctionFactory);
|
||||
this.cs = cs;
|
||||
this.background = dict.has('Background') ?
|
||||
cs.getRgb(dict.get('Background'), 0) : null;
|
||||
this.background = dict.has("Background")
|
||||
? cs.getRgb(dict.get("Background"), 0)
|
||||
: null;
|
||||
|
||||
var fnObj = dict.get('Function');
|
||||
var fnObj = dict.get("Function");
|
||||
var fn = fnObj ? pdfFunctionFactory.createFromArray(fnObj) : null;
|
||||
|
||||
this.coords = [];
|
||||
@ -745,10 +856,10 @@ Shadings.Mesh = (function MeshClosure() {
|
||||
this.figures = [];
|
||||
|
||||
var decodeContext = {
|
||||
bitsPerCoordinate: dict.get('BitsPerCoordinate'),
|
||||
bitsPerComponent: dict.get('BitsPerComponent'),
|
||||
bitsPerFlag: dict.get('BitsPerFlag'),
|
||||
decode: dict.getArray('Decode'),
|
||||
bitsPerCoordinate: dict.get("BitsPerCoordinate"),
|
||||
bitsPerComponent: dict.get("BitsPerComponent"),
|
||||
bitsPerFlag: dict.get("BitsPerFlag"),
|
||||
decode: dict.getArray("Decode"),
|
||||
colorFn: fn,
|
||||
colorSpace: cs,
|
||||
numComps: fn ? 1 : cs.numComps,
|
||||
@ -761,9 +872,9 @@ Shadings.Mesh = (function MeshClosure() {
|
||||
decodeType4Shading(this, reader);
|
||||
break;
|
||||
case ShadingType.LATTICE_FORM_MESH:
|
||||
var verticesPerRow = dict.get('VerticesPerRow') | 0;
|
||||
var verticesPerRow = dict.get("VerticesPerRow") | 0;
|
||||
if (verticesPerRow < 2) {
|
||||
throw new FormatError('Invalid VerticesPerRow');
|
||||
throw new FormatError("Invalid VerticesPerRow");
|
||||
}
|
||||
decodeType5Shading(this, reader, verticesPerRow);
|
||||
break;
|
||||
@ -776,7 +887,7 @@ Shadings.Mesh = (function MeshClosure() {
|
||||
patchMesh = true;
|
||||
break;
|
||||
default:
|
||||
unreachable('Unsupported mesh type.');
|
||||
unreachable("Unsupported mesh type.");
|
||||
break;
|
||||
}
|
||||
|
||||
@ -795,8 +906,17 @@ Shadings.Mesh = (function MeshClosure() {
|
||||
|
||||
Mesh.prototype = {
|
||||
getIR: function Mesh_getIR() {
|
||||
return ['Mesh', this.shadingType, this.coords, this.colors, this.figures,
|
||||
this.bounds, this.matrix, this.bbox, this.background];
|
||||
return [
|
||||
"Mesh",
|
||||
this.shadingType,
|
||||
this.coords,
|
||||
this.colors,
|
||||
this.figures,
|
||||
this.bounds,
|
||||
this.matrix,
|
||||
this.bbox,
|
||||
this.background,
|
||||
];
|
||||
},
|
||||
};
|
||||
|
||||
@ -805,38 +925,42 @@ Shadings.Mesh = (function MeshClosure() {
|
||||
|
||||
Shadings.Dummy = (function DummyClosure() {
|
||||
function Dummy() {
|
||||
this.type = 'Pattern';
|
||||
this.type = "Pattern";
|
||||
}
|
||||
|
||||
Dummy.prototype = {
|
||||
getIR: function Dummy_getIR() {
|
||||
return ['Dummy'];
|
||||
return ["Dummy"];
|
||||
},
|
||||
};
|
||||
return Dummy;
|
||||
})();
|
||||
|
||||
function getTilingPatternIR(operatorList, dict, args) {
|
||||
let matrix = dict.getArray('Matrix');
|
||||
let bbox = Util.normalizeRect(dict.getArray('BBox'));
|
||||
let xstep = dict.get('XStep');
|
||||
let ystep = dict.get('YStep');
|
||||
let paintType = dict.get('PaintType');
|
||||
let tilingType = dict.get('TilingType');
|
||||
let matrix = dict.getArray("Matrix");
|
||||
let bbox = Util.normalizeRect(dict.getArray("BBox"));
|
||||
let xstep = dict.get("XStep");
|
||||
let ystep = dict.get("YStep");
|
||||
let paintType = dict.get("PaintType");
|
||||
let tilingType = dict.get("TilingType");
|
||||
|
||||
// Ensure that the pattern has a non-zero width and height, to prevent errors
|
||||
// in `pattern_helper.js` (fixes issue8330.pdf).
|
||||
if ((bbox[2] - bbox[0]) === 0 || (bbox[3] - bbox[1]) === 0) {
|
||||
if (bbox[2] - bbox[0] === 0 || bbox[3] - bbox[1] === 0) {
|
||||
throw new FormatError(`Invalid getTilingPatternIR /BBox array: [${bbox}].`);
|
||||
}
|
||||
|
||||
return [
|
||||
'TilingPattern', args, operatorList, matrix, bbox, xstep, ystep,
|
||||
paintType, tilingType
|
||||
"TilingPattern",
|
||||
args,
|
||||
operatorList,
|
||||
matrix,
|
||||
bbox,
|
||||
xstep,
|
||||
ystep,
|
||||
paintType,
|
||||
tilingType,
|
||||
];
|
||||
}
|
||||
|
||||
export {
|
||||
Pattern,
|
||||
getTilingPatternIR,
|
||||
};
|
||||
export { Pattern, getTilingPatternIR };
|
||||
|
@ -14,17 +14,20 @@
|
||||
*/
|
||||
|
||||
import {
|
||||
createValidAbsoluteUrl, shadow, unreachable, warn
|
||||
} from '../shared/util';
|
||||
import { ChunkedStreamManager } from './chunked_stream';
|
||||
import { MissingDataException } from './core_utils';
|
||||
import { PDFDocument } from './document';
|
||||
import { Stream } from './stream';
|
||||
createValidAbsoluteUrl,
|
||||
shadow,
|
||||
unreachable,
|
||||
warn,
|
||||
} from "../shared/util";
|
||||
import { ChunkedStreamManager } from "./chunked_stream";
|
||||
import { MissingDataException } from "./core_utils";
|
||||
import { PDFDocument } from "./document";
|
||||
import { Stream } from "./stream";
|
||||
|
||||
class BasePdfManager {
|
||||
constructor() {
|
||||
if (this.constructor === BasePdfManager) {
|
||||
unreachable('Cannot initialize BasePdfManager.');
|
||||
unreachable("Cannot initialize BasePdfManager.");
|
||||
}
|
||||
}
|
||||
|
||||
@ -46,11 +49,11 @@ class BasePdfManager {
|
||||
warn(`Invalid absolute docBaseUrl: "${this._docBaseUrl}".`);
|
||||
}
|
||||
}
|
||||
return shadow(this, 'docBaseUrl', docBaseUrl);
|
||||
return shadow(this, "docBaseUrl", docBaseUrl);
|
||||
}
|
||||
|
||||
onLoadedStream() {
|
||||
unreachable('Abstract method `onLoadedStream` called');
|
||||
unreachable("Abstract method `onLoadedStream` called");
|
||||
}
|
||||
|
||||
ensureDoc(prop, args) {
|
||||
@ -78,19 +81,19 @@ class BasePdfManager {
|
||||
}
|
||||
|
||||
async ensure(obj, prop, args) {
|
||||
unreachable('Abstract method `ensure` called');
|
||||
unreachable("Abstract method `ensure` called");
|
||||
}
|
||||
|
||||
requestRange(begin, end) {
|
||||
unreachable('Abstract method `requestRange` called');
|
||||
unreachable("Abstract method `requestRange` called");
|
||||
}
|
||||
|
||||
requestLoadedStream() {
|
||||
unreachable('Abstract method `requestLoadedStream` called');
|
||||
unreachable("Abstract method `requestLoadedStream` called");
|
||||
}
|
||||
|
||||
sendProgressiveData(chunk) {
|
||||
unreachable('Abstract method `sendProgressiveData` called');
|
||||
unreachable("Abstract method `sendProgressiveData` called");
|
||||
}
|
||||
|
||||
updatePassword(password) {
|
||||
@ -98,7 +101,7 @@ class BasePdfManager {
|
||||
}
|
||||
|
||||
terminate(reason) {
|
||||
unreachable('Abstract method `terminate` called');
|
||||
unreachable("Abstract method `terminate` called");
|
||||
}
|
||||
}
|
||||
|
||||
@ -118,7 +121,7 @@ class LocalPdfManager extends BasePdfManager {
|
||||
|
||||
async ensure(obj, prop, args) {
|
||||
const value = obj[prop];
|
||||
if (typeof value === 'function') {
|
||||
if (typeof value === "function") {
|
||||
return value.apply(obj, args);
|
||||
}
|
||||
return value;
|
||||
@ -159,7 +162,7 @@ class NetworkPdfManager extends BasePdfManager {
|
||||
async ensure(obj, prop, args) {
|
||||
try {
|
||||
const value = obj[prop];
|
||||
if (typeof value === 'function') {
|
||||
if (typeof value === "function") {
|
||||
return value.apply(obj, args);
|
||||
}
|
||||
return value;
|
||||
@ -181,7 +184,7 @@ class NetworkPdfManager extends BasePdfManager {
|
||||
}
|
||||
|
||||
sendProgressiveData(chunk) {
|
||||
this.streamManager.onReceiveData({ chunk, });
|
||||
this.streamManager.onReceiveData({ chunk });
|
||||
}
|
||||
|
||||
onLoadedStream() {
|
||||
@ -193,7 +196,4 @@ class NetworkPdfManager extends BasePdfManager {
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
LocalPdfManager,
|
||||
NetworkPdfManager,
|
||||
};
|
||||
export { LocalPdfManager, NetworkPdfManager };
|
||||
|
@ -14,7 +14,7 @@
|
||||
*/
|
||||
/* uses XRef */
|
||||
|
||||
import { assert } from '../shared/util';
|
||||
import { assert } from "../shared/util";
|
||||
|
||||
var EOF = {};
|
||||
|
||||
@ -29,7 +29,7 @@ var Name = (function NameClosure() {
|
||||
|
||||
Name.get = function Name_get(name) {
|
||||
var nameValue = nameCache[name];
|
||||
return (nameValue ? nameValue : (nameCache[name] = new Name(name)));
|
||||
return nameValue ? nameValue : (nameCache[name] = new Name(name));
|
||||
};
|
||||
|
||||
Name._clearCache = function() {
|
||||
@ -50,7 +50,7 @@ var Cmd = (function CmdClosure() {
|
||||
|
||||
Cmd.get = function Cmd_get(cmd) {
|
||||
var cmdValue = cmdCache[cmd];
|
||||
return (cmdValue ? cmdValue : (cmdCache[cmd] = new Cmd(cmd)));
|
||||
return cmdValue ? cmdValue : (cmdCache[cmd] = new Cmd(cmd));
|
||||
};
|
||||
|
||||
Cmd._clearCache = function() {
|
||||
@ -193,9 +193,9 @@ var Ref = (function RefClosure() {
|
||||
};
|
||||
|
||||
Ref.get = function(num, gen) {
|
||||
const key = (gen === 0 ? `${num}R` : `${num}R${gen}`);
|
||||
const key = gen === 0 ? `${num}R` : `${num}R${gen}`;
|
||||
const refValue = refCache[key];
|
||||
return (refValue ? refValue : (refCache[key] = new Ref(num, gen)));
|
||||
return refValue ? refValue : (refCache[key] = new Ref(num, gen));
|
||||
};
|
||||
|
||||
Ref._clearCache = function() {
|
||||
@ -266,7 +266,7 @@ var RefSetCache = (function RefSetCacheClosure() {
|
||||
})();
|
||||
|
||||
function isEOF(v) {
|
||||
return (v === EOF);
|
||||
return v === EOF;
|
||||
}
|
||||
|
||||
function isName(v, name) {
|
||||
@ -278,8 +278,9 @@ function isCmd(v, cmd) {
|
||||
}
|
||||
|
||||
function isDict(v, type) {
|
||||
return v instanceof Dict &&
|
||||
(type === undefined || isName(v.get('Type'), type));
|
||||
return (
|
||||
v instanceof Dict && (type === undefined || isName(v.get("Type"), type))
|
||||
);
|
||||
}
|
||||
|
||||
function isRef(v) {
|
||||
@ -287,16 +288,20 @@ function isRef(v) {
|
||||
}
|
||||
|
||||
function isRefsEqual(v1, v2) {
|
||||
if (typeof PDFJSDev === 'undefined' ||
|
||||
PDFJSDev.test('!PRODUCTION || TESTING')) {
|
||||
assert(v1 instanceof Ref && v2 instanceof Ref,
|
||||
'isRefsEqual: Both parameters should be `Ref`s.');
|
||||
if (
|
||||
typeof PDFJSDev === "undefined" ||
|
||||
PDFJSDev.test("!PRODUCTION || TESTING")
|
||||
) {
|
||||
assert(
|
||||
v1 instanceof Ref && v2 instanceof Ref,
|
||||
"isRefsEqual: Both parameters should be `Ref`s."
|
||||
);
|
||||
}
|
||||
return v1.num === v2.num && v1.gen === v2.gen;
|
||||
}
|
||||
|
||||
function isStream(v) {
|
||||
return typeof v === 'object' && v !== null && v.getBytes !== undefined;
|
||||
return typeof v === "object" && v !== null && v.getBytes !== undefined;
|
||||
}
|
||||
|
||||
function clearPrimitiveCaches() {
|
||||
|
@ -14,8 +14,8 @@
|
||||
*/
|
||||
/* eslint no-var: error */
|
||||
|
||||
import { FormatError, isSpace, shadow } from '../shared/util';
|
||||
import { EOF } from './primitives';
|
||||
import { FormatError, isSpace, shadow } from "../shared/util";
|
||||
import { EOF } from "./primitives";
|
||||
|
||||
class PostScriptParser {
|
||||
constructor(lexer) {
|
||||
@ -43,7 +43,8 @@ class PostScriptParser {
|
||||
return true;
|
||||
}
|
||||
throw new FormatError(
|
||||
`Unexpected symbol: found ${this.token.type} expected ${type}.`);
|
||||
`Unexpected symbol: found ${this.token.type} expected ${type}.`
|
||||
);
|
||||
}
|
||||
|
||||
parse() {
|
||||
@ -79,7 +80,7 @@ class PostScriptParser {
|
||||
// The true block is right after the 'if' so it just falls through on true
|
||||
// else it jumps and skips the true block.
|
||||
this.operators[conditionLocation] = this.operators.length;
|
||||
this.operators[conditionLocation + 1] = 'jz';
|
||||
this.operators[conditionLocation + 1] = "jz";
|
||||
} else if (this.accept(PostScriptTokenTypes.LBRACE)) {
|
||||
const jumpLocation = this.operators.length;
|
||||
this.operators.push(null, null);
|
||||
@ -89,12 +90,12 @@ class PostScriptParser {
|
||||
this.expect(PostScriptTokenTypes.IFELSE);
|
||||
// The jump is added at the end of the true block to skip the false block.
|
||||
this.operators[jumpLocation] = this.operators.length;
|
||||
this.operators[jumpLocation + 1] = 'j';
|
||||
this.operators[jumpLocation + 1] = "j";
|
||||
|
||||
this.operators[conditionLocation] = endOfTrue;
|
||||
this.operators[conditionLocation + 1] = 'jz';
|
||||
this.operators[conditionLocation + 1] = "jz";
|
||||
} else {
|
||||
throw new FormatError('PS Function: error parsing conditional.');
|
||||
throw new FormatError("PS Function: error parsing conditional.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -122,28 +123,42 @@ const PostScriptToken = (function PostScriptTokenClosure() {
|
||||
if (opValue) {
|
||||
return opValue;
|
||||
}
|
||||
return opCache[op] = new PostScriptToken(PostScriptTokenTypes.OPERATOR,
|
||||
op);
|
||||
return (opCache[op] = new PostScriptToken(
|
||||
PostScriptTokenTypes.OPERATOR,
|
||||
op
|
||||
));
|
||||
}
|
||||
|
||||
static get LBRACE() {
|
||||
return shadow(this, 'LBRACE',
|
||||
new PostScriptToken(PostScriptTokenTypes.LBRACE, '{'));
|
||||
return shadow(
|
||||
this,
|
||||
"LBRACE",
|
||||
new PostScriptToken(PostScriptTokenTypes.LBRACE, "{")
|
||||
);
|
||||
}
|
||||
|
||||
static get RBRACE() {
|
||||
return shadow(this, 'RBRACE',
|
||||
new PostScriptToken(PostScriptTokenTypes.RBRACE, '}'));
|
||||
return shadow(
|
||||
this,
|
||||
"RBRACE",
|
||||
new PostScriptToken(PostScriptTokenTypes.RBRACE, "}")
|
||||
);
|
||||
}
|
||||
|
||||
static get IF() {
|
||||
return shadow(this, 'IF',
|
||||
new PostScriptToken(PostScriptTokenTypes.IF, 'IF'));
|
||||
return shadow(
|
||||
this,
|
||||
"IF",
|
||||
new PostScriptToken(PostScriptTokenTypes.IF, "IF")
|
||||
);
|
||||
}
|
||||
|
||||
static get IFELSE() {
|
||||
return shadow(this, 'IFELSE',
|
||||
new PostScriptToken(PostScriptTokenTypes.IFELSE, 'IFELSE'));
|
||||
return shadow(
|
||||
this,
|
||||
"IFELSE",
|
||||
new PostScriptToken(PostScriptTokenTypes.IFELSE, "IFELSE")
|
||||
);
|
||||
}
|
||||
}
|
||||
return PostScriptToken;
|
||||
@ -172,10 +187,10 @@ class PostScriptLexer {
|
||||
}
|
||||
|
||||
if (comment) {
|
||||
if (ch === 0x0A || ch === 0x0D) {
|
||||
if (ch === 0x0a || ch === 0x0d) {
|
||||
comment = false;
|
||||
}
|
||||
} else if (ch === 0x25) { // '%'
|
||||
} else if (ch === /* '%' = */ 0x25) {
|
||||
comment = true;
|
||||
} else if (!isSpace(ch)) {
|
||||
break;
|
||||
@ -183,15 +198,27 @@ class PostScriptLexer {
|
||||
ch = this.nextChar();
|
||||
}
|
||||
switch (ch | 0) {
|
||||
case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: // '0'-'4'
|
||||
case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: // '5'-'9'
|
||||
case 0x2B: case 0x2D: case 0x2E: // '+', '-', '.'
|
||||
return new PostScriptToken(PostScriptTokenTypes.NUMBER,
|
||||
this.getNumber());
|
||||
case 0x7B: // '{'
|
||||
case 0x30: // '0'
|
||||
case 0x31: // '1'
|
||||
case 0x32: // '2'
|
||||
case 0x33: // '3'
|
||||
case 0x34: // '4'
|
||||
case 0x35: // '5'
|
||||
case 0x36: // '6'
|
||||
case 0x37: // '7'
|
||||
case 0x38: // '8'
|
||||
case 0x39: // '9'
|
||||
case 0x2b: // '+'
|
||||
case 0x2d: // '-'
|
||||
case 0x2e: // '.'
|
||||
return new PostScriptToken(
|
||||
PostScriptTokenTypes.NUMBER,
|
||||
this.getNumber()
|
||||
);
|
||||
case 0x7b: // '{'
|
||||
this.nextChar();
|
||||
return PostScriptToken.LBRACE;
|
||||
case 0x7D: // '}'
|
||||
case 0x7d: // '}'
|
||||
this.nextChar();
|
||||
return PostScriptToken.RBRACE;
|
||||
}
|
||||
@ -200,15 +227,18 @@ class PostScriptLexer {
|
||||
strBuf.length = 0;
|
||||
strBuf[0] = String.fromCharCode(ch);
|
||||
|
||||
while ((ch = this.nextChar()) >= 0 && // and 'A'-'Z', 'a'-'z'
|
||||
((ch >= 0x41 && ch <= 0x5A) || (ch >= 0x61 && ch <= 0x7A))) {
|
||||
while (
|
||||
(ch = this.nextChar()) >= 0 &&
|
||||
((ch >= /* 'A' = */ 0x41 && ch <= /* 'Z' = */ 0x5a) ||
|
||||
(ch >= /* 'a' = */ 0x61 && ch <= /* 'z' = */ 0x7a))
|
||||
) {
|
||||
strBuf.push(String.fromCharCode(ch));
|
||||
}
|
||||
const str = strBuf.join('');
|
||||
const str = strBuf.join("");
|
||||
switch (str.toLowerCase()) {
|
||||
case 'if':
|
||||
case "if":
|
||||
return PostScriptToken.IF;
|
||||
case 'ifelse':
|
||||
case "ifelse":
|
||||
return PostScriptToken.IFELSE;
|
||||
default:
|
||||
return PostScriptToken.getOperator(str);
|
||||
@ -222,14 +252,17 @@ class PostScriptLexer {
|
||||
strBuf[0] = String.fromCharCode(ch);
|
||||
|
||||
while ((ch = this.nextChar()) >= 0) {
|
||||
if ((ch >= 0x30 && ch <= 0x39) || // '0'-'9'
|
||||
ch === 0x2D || ch === 0x2E) { // '-', '.'
|
||||
if (
|
||||
(ch >= /* '0' = */ 0x30 && ch <= /* '9' = */ 0x39) ||
|
||||
ch === /* '-' = */ 0x2d ||
|
||||
ch === /* '.' = */ 0x2e
|
||||
) {
|
||||
strBuf.push(String.fromCharCode(ch));
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
const value = parseFloat(strBuf.join(''));
|
||||
const value = parseFloat(strBuf.join(""));
|
||||
if (isNaN(value)) {
|
||||
throw new FormatError(`Invalid floating point number: ${value}`);
|
||||
}
|
||||
@ -237,7 +270,4 @@ class PostScriptLexer {
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
PostScriptLexer,
|
||||
PostScriptParser,
|
||||
};
|
||||
export { PostScriptLexer, PostScriptParser };
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -20,17 +20,22 @@
|
||||
*/
|
||||
|
||||
import {
|
||||
FormatError, isSpace, stringToBytes, unreachable
|
||||
} from '../shared/util';
|
||||
import { isDict } from './primitives';
|
||||
FormatError,
|
||||
isSpace,
|
||||
stringToBytes,
|
||||
unreachable,
|
||||
} from "../shared/util";
|
||||
import { isDict } from "./primitives";
|
||||
|
||||
var Stream = (function StreamClosure() {
|
||||
function Stream(arrayBuffer, start, length, dict) {
|
||||
this.bytes = (arrayBuffer instanceof Uint8Array ?
|
||||
arrayBuffer : new Uint8Array(arrayBuffer));
|
||||
this.bytes =
|
||||
arrayBuffer instanceof Uint8Array
|
||||
? arrayBuffer
|
||||
: new Uint8Array(arrayBuffer);
|
||||
this.start = start || 0;
|
||||
this.pos = this.start;
|
||||
this.end = (start + length) || this.bytes.length;
|
||||
this.end = start + length || this.bytes.length;
|
||||
this.dict = dict;
|
||||
}
|
||||
|
||||
@ -73,7 +78,7 @@ var Stream = (function StreamClosure() {
|
||||
if (!length) {
|
||||
let subarray = bytes.subarray(pos, strEnd);
|
||||
// `this.bytes` is always a `Uint8Array` here.
|
||||
return (forceClamped ? new Uint8ClampedArray(subarray) : subarray);
|
||||
return forceClamped ? new Uint8ClampedArray(subarray) : subarray;
|
||||
}
|
||||
var end = pos + length;
|
||||
if (end > strEnd) {
|
||||
@ -82,7 +87,7 @@ var Stream = (function StreamClosure() {
|
||||
this.pos = end;
|
||||
let subarray = bytes.subarray(pos, end);
|
||||
// `this.bytes` is always a `Uint8Array` here.
|
||||
return (forceClamped ? new Uint8ClampedArray(subarray) : subarray);
|
||||
return forceClamped ? new Uint8ClampedArray(subarray) : subarray;
|
||||
},
|
||||
peekByte: function Stream_peekByte() {
|
||||
var peekedByte = this.getByte();
|
||||
@ -208,7 +213,8 @@ var DecodeStream = (function DecodeStreamClosure() {
|
||||
return (b0 << 24) + (b1 << 16) + (b2 << 8) + b3;
|
||||
},
|
||||
getBytes(length, forceClamped = false) {
|
||||
var end, pos = this.pos;
|
||||
var end,
|
||||
pos = this.pos;
|
||||
|
||||
if (length) {
|
||||
this.ensureBuffer(pos + length);
|
||||
@ -231,8 +237,9 @@ var DecodeStream = (function DecodeStreamClosure() {
|
||||
this.pos = end;
|
||||
let subarray = this.buffer.subarray(pos, end);
|
||||
// `this.buffer` is either a `Uint8Array` or `Uint8ClampedArray` here.
|
||||
return (forceClamped && !(subarray instanceof Uint8ClampedArray) ?
|
||||
new Uint8ClampedArray(subarray) : subarray);
|
||||
return forceClamped && !(subarray instanceof Uint8ClampedArray)
|
||||
? new Uint8ClampedArray(subarray)
|
||||
: subarray;
|
||||
},
|
||||
peekByte: function DecodeStream_peekByte() {
|
||||
var peekedByte = this.getByte();
|
||||
@ -255,7 +262,7 @@ var DecodeStream = (function DecodeStreamClosure() {
|
||||
},
|
||||
|
||||
getByteRange(begin, end) {
|
||||
unreachable('Should not call DecodeStream.getByteRange');
|
||||
unreachable("Should not call DecodeStream.getByteRange");
|
||||
},
|
||||
|
||||
skip: function DecodeStream_skip(n) {
|
||||
@ -296,9 +303,7 @@ var StreamsSequenceStream = (function StreamsSequenceStreamClosure() {
|
||||
|
||||
StreamsSequenceStream.prototype = Object.create(DecodeStream.prototype);
|
||||
|
||||
StreamsSequenceStream.prototype.readBlock =
|
||||
function streamSequenceStreamReadBlock() {
|
||||
|
||||
StreamsSequenceStream.prototype.readBlock = function streamSequenceStreamReadBlock() {
|
||||
var streams = this.streams;
|
||||
if (streams.length === 0) {
|
||||
this.eof = true;
|
||||
@ -313,9 +318,7 @@ var StreamsSequenceStream = (function StreamsSequenceStreamClosure() {
|
||||
this.bufferLength = newLength;
|
||||
};
|
||||
|
||||
StreamsSequenceStream.prototype.getBaseStreams =
|
||||
function StreamsSequenceStream_getBaseStreams() {
|
||||
|
||||
StreamsSequenceStream.prototype.getBaseStreams = function StreamsSequenceStream_getBaseStreams() {
|
||||
var baseStreams = [];
|
||||
for (var i = 0, ii = this.streams.length; i < ii; i++) {
|
||||
var stream = this.streams[i];
|
||||
@ -330,10 +333,12 @@ var StreamsSequenceStream = (function StreamsSequenceStreamClosure() {
|
||||
})();
|
||||
|
||||
var FlateStream = (function FlateStreamClosure() {
|
||||
// prettier-ignore
|
||||
var codeLenCodeMap = new Int32Array([
|
||||
16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
|
||||
]);
|
||||
|
||||
// prettier-ignore
|
||||
var lengthDecode = new Int32Array([
|
||||
0x00003, 0x00004, 0x00005, 0x00006, 0x00007, 0x00008, 0x00009, 0x0000a,
|
||||
0x1000b, 0x1000d, 0x1000f, 0x10011, 0x20013, 0x20017, 0x2001b, 0x2001f,
|
||||
@ -341,6 +346,7 @@ var FlateStream = (function FlateStreamClosure() {
|
||||
0x50083, 0x500a3, 0x500c3, 0x500e3, 0x00102, 0x00102, 0x00102
|
||||
]);
|
||||
|
||||
// prettier-ignore
|
||||
var distDecode = new Int32Array([
|
||||
0x00001, 0x00002, 0x00003, 0x00004, 0x10005, 0x10007, 0x20009, 0x2000d,
|
||||
0x30011, 0x30019, 0x40021, 0x40031, 0x50041, 0x50061, 0x60081, 0x600c1,
|
||||
@ -348,6 +354,7 @@ var FlateStream = (function FlateStreamClosure() {
|
||||
0xb1001, 0xb1801, 0xc2001, 0xc3001, 0xd4001, 0xd6001
|
||||
]);
|
||||
|
||||
// prettier-ignore
|
||||
var fixedLitCodeTab = [new Int32Array([
|
||||
0x70100, 0x80050, 0x80010, 0x80118, 0x70110, 0x80070, 0x80030, 0x900c0,
|
||||
0x70108, 0x80060, 0x80020, 0x900a0, 0x80000, 0x80080, 0x80040, 0x900e0,
|
||||
@ -415,6 +422,7 @@ var FlateStream = (function FlateStreamClosure() {
|
||||
0x7010f, 0x8006f, 0x8002f, 0x900bf, 0x8000f, 0x8008f, 0x8004f, 0x900ff
|
||||
]), 9];
|
||||
|
||||
// prettier-ignore
|
||||
var fixedDistCodeTab = [new Int32Array([
|
||||
0x50000, 0x50010, 0x50008, 0x50018, 0x50004, 0x50014, 0x5000c, 0x5001c,
|
||||
0x50002, 0x50012, 0x5000a, 0x5001a, 0x50006, 0x50016, 0x5000e, 0x00000,
|
||||
@ -429,19 +437,18 @@ var FlateStream = (function FlateStreamClosure() {
|
||||
var cmf = str.getByte();
|
||||
var flg = str.getByte();
|
||||
if (cmf === -1 || flg === -1) {
|
||||
throw new FormatError(
|
||||
`Invalid header in flate stream: ${cmf}, ${flg}`);
|
||||
throw new FormatError(`Invalid header in flate stream: ${cmf}, ${flg}`);
|
||||
}
|
||||
if ((cmf & 0x0f) !== 0x08) {
|
||||
throw new FormatError(
|
||||
`Unknown compression method in flate stream: ${cmf}, ${flg}`);
|
||||
`Unknown compression method in flate stream: ${cmf}, ${flg}`
|
||||
);
|
||||
}
|
||||
if ((((cmf << 8) + flg) % 31) !== 0) {
|
||||
if (((cmf << 8) + flg) % 31 !== 0) {
|
||||
throw new FormatError(`Bad FCHECK in flate stream: ${cmf}, ${flg}`);
|
||||
}
|
||||
if (flg & 0x20) {
|
||||
throw new FormatError(
|
||||
`FDICT bit set in flate stream: ${cmf}, ${flg}`);
|
||||
throw new FormatError(`FDICT bit set in flate stream: ${cmf}, ${flg}`);
|
||||
}
|
||||
|
||||
this.codeSize = 0;
|
||||
@ -460,7 +467,7 @@ var FlateStream = (function FlateStreamClosure() {
|
||||
var b;
|
||||
while (codeSize < bits) {
|
||||
if ((b = str.getByte()) === -1) {
|
||||
throw new FormatError('Bad encoding in flate stream');
|
||||
throw new FormatError("Bad encoding in flate stream");
|
||||
}
|
||||
codeBuf |= b << codeSize;
|
||||
codeSize += 8;
|
||||
@ -486,22 +493,23 @@ var FlateStream = (function FlateStreamClosure() {
|
||||
// codeSize < codeLen check below guards against incomplete codeVal.
|
||||
break;
|
||||
}
|
||||
codeBuf |= (b << codeSize);
|
||||
codeBuf |= b << codeSize;
|
||||
codeSize += 8;
|
||||
}
|
||||
var code = codes[codeBuf & ((1 << maxLen) - 1)];
|
||||
var codeLen = code >> 16;
|
||||
var codeVal = code & 0xffff;
|
||||
if (codeLen < 1 || codeSize < codeLen) {
|
||||
throw new FormatError('Bad encoding in flate stream');
|
||||
throw new FormatError("Bad encoding in flate stream");
|
||||
}
|
||||
this.codeBuf = (codeBuf >> codeLen);
|
||||
this.codeSize = (codeSize - codeLen);
|
||||
this.codeBuf = codeBuf >> codeLen;
|
||||
this.codeSize = codeSize - codeLen;
|
||||
return codeVal;
|
||||
};
|
||||
|
||||
FlateStream.prototype.generateHuffmanTable =
|
||||
function flateStreamGenerateHuffmanTable(lengths) {
|
||||
FlateStream.prototype.generateHuffmanTable = function flateStreamGenerateHuffmanTable(
|
||||
lengths
|
||||
) {
|
||||
var n = lengths.length;
|
||||
|
||||
// find max code length
|
||||
@ -516,9 +524,11 @@ var FlateStream = (function FlateStreamClosure() {
|
||||
// build the table
|
||||
var size = 1 << maxLen;
|
||||
var codes = new Int32Array(size);
|
||||
for (var len = 1, code = 0, skip = 2;
|
||||
len <= maxLen;
|
||||
++len, code <<= 1, skip <<= 1) {
|
||||
for (
|
||||
var len = 1, code = 0, skip = 2;
|
||||
len <= maxLen;
|
||||
++len, code <<= 1, skip <<= 1
|
||||
) {
|
||||
for (var val = 0; val < n; ++val) {
|
||||
if (lengths[val] === len) {
|
||||
// bit-reverse the code
|
||||
@ -551,36 +561,36 @@ var FlateStream = (function FlateStreamClosure() {
|
||||
}
|
||||
hdr >>= 1;
|
||||
|
||||
if (hdr === 0) { // uncompressed block
|
||||
if (hdr === 0) {
|
||||
// uncompressed block
|
||||
var b;
|
||||
|
||||
if ((b = str.getByte()) === -1) {
|
||||
throw new FormatError('Bad block header in flate stream');
|
||||
throw new FormatError("Bad block header in flate stream");
|
||||
}
|
||||
var blockLen = b;
|
||||
if ((b = str.getByte()) === -1) {
|
||||
throw new FormatError('Bad block header in flate stream');
|
||||
throw new FormatError("Bad block header in flate stream");
|
||||
}
|
||||
blockLen |= (b << 8);
|
||||
blockLen |= b << 8;
|
||||
if ((b = str.getByte()) === -1) {
|
||||
throw new FormatError('Bad block header in flate stream');
|
||||
throw new FormatError("Bad block header in flate stream");
|
||||
}
|
||||
var check = b;
|
||||
if ((b = str.getByte()) === -1) {
|
||||
throw new FormatError('Bad block header in flate stream');
|
||||
throw new FormatError("Bad block header in flate stream");
|
||||
}
|
||||
check |= (b << 8);
|
||||
if (check !== (~blockLen & 0xffff) &&
|
||||
(blockLen !== 0 || check !== 0)) {
|
||||
check |= b << 8;
|
||||
if (check !== (~blockLen & 0xffff) && (blockLen !== 0 || check !== 0)) {
|
||||
// Ignoring error for bad "empty" block (see issue 1277)
|
||||
throw new FormatError(
|
||||
'Bad uncompressed block length in flate stream');
|
||||
throw new FormatError("Bad uncompressed block length in flate stream");
|
||||
}
|
||||
|
||||
this.codeBuf = 0;
|
||||
this.codeSize = 0;
|
||||
|
||||
const bufferLength = this.bufferLength, end = bufferLength + blockLen;
|
||||
const bufferLength = this.bufferLength,
|
||||
end = bufferLength + blockLen;
|
||||
buffer = this.ensureBuffer(end);
|
||||
this.bufferLength = end;
|
||||
|
||||
@ -600,10 +610,12 @@ var FlateStream = (function FlateStreamClosure() {
|
||||
|
||||
var litCodeTable;
|
||||
var distCodeTable;
|
||||
if (hdr === 1) { // compressed block, fixed codes
|
||||
if (hdr === 1) {
|
||||
// compressed block, fixed codes
|
||||
litCodeTable = fixedLitCodeTab;
|
||||
distCodeTable = fixedDistCodeTab;
|
||||
} else if (hdr === 2) { // compressed block, dynamic codes
|
||||
} else if (hdr === 2) {
|
||||
// compressed block, dynamic codes
|
||||
var numLitCodes = this.getBits(5) + 257;
|
||||
var numDistCodes = this.getBits(5) + 1;
|
||||
var numCodeLenCodes = this.getBits(4) + 4;
|
||||
@ -626,11 +638,17 @@ var FlateStream = (function FlateStreamClosure() {
|
||||
while (i < codes) {
|
||||
var code = this.getCode(codeLenCodeTab);
|
||||
if (code === 16) {
|
||||
bitsLength = 2; bitsOffset = 3; what = len;
|
||||
bitsLength = 2;
|
||||
bitsOffset = 3;
|
||||
what = len;
|
||||
} else if (code === 17) {
|
||||
bitsLength = 3; bitsOffset = 3; what = (len = 0);
|
||||
bitsLength = 3;
|
||||
bitsOffset = 3;
|
||||
what = len = 0;
|
||||
} else if (code === 18) {
|
||||
bitsLength = 7; bitsOffset = 11; what = (len = 0);
|
||||
bitsLength = 7;
|
||||
bitsOffset = 11;
|
||||
what = len = 0;
|
||||
} else {
|
||||
codeLengths[i++] = len = code;
|
||||
continue;
|
||||
@ -642,12 +660,14 @@ var FlateStream = (function FlateStreamClosure() {
|
||||
}
|
||||
}
|
||||
|
||||
litCodeTable =
|
||||
this.generateHuffmanTable(codeLengths.subarray(0, numLitCodes));
|
||||
distCodeTable =
|
||||
this.generateHuffmanTable(codeLengths.subarray(numLitCodes, codes));
|
||||
litCodeTable = this.generateHuffmanTable(
|
||||
codeLengths.subarray(0, numLitCodes)
|
||||
);
|
||||
distCodeTable = this.generateHuffmanTable(
|
||||
codeLengths.subarray(numLitCodes, codes)
|
||||
);
|
||||
} else {
|
||||
throw new FormatError('Unknown block type in flate stream');
|
||||
throw new FormatError("Unknown block type in flate stream");
|
||||
}
|
||||
|
||||
buffer = this.buffer;
|
||||
@ -699,7 +719,7 @@ var PredictorStream = (function PredictorStreamClosure() {
|
||||
if (!isDict(params)) {
|
||||
return str; // no prediction
|
||||
}
|
||||
var predictor = this.predictor = params.get('Predictor') || 1;
|
||||
var predictor = (this.predictor = params.get("Predictor") || 1);
|
||||
|
||||
if (predictor <= 1) {
|
||||
return str; // no prediction
|
||||
@ -717,9 +737,9 @@ var PredictorStream = (function PredictorStreamClosure() {
|
||||
this.str = str;
|
||||
this.dict = str.dict;
|
||||
|
||||
var colors = this.colors = params.get('Colors') || 1;
|
||||
var bits = this.bits = params.get('BitsPerComponent') || 8;
|
||||
var columns = this.columns = params.get('Columns') || 1;
|
||||
var colors = (this.colors = params.get("Colors") || 1);
|
||||
var bits = (this.bits = params.get("BitsPerComponent") || 8);
|
||||
var columns = (this.columns = params.get("Columns") || 1);
|
||||
|
||||
this.pixBytes = (colors * bits + 7) >> 3;
|
||||
this.rowBytes = (columns * colors * bits + 7) >> 3;
|
||||
@ -730,8 +750,7 @@ var PredictorStream = (function PredictorStreamClosure() {
|
||||
|
||||
PredictorStream.prototype = Object.create(DecodeStream.prototype);
|
||||
|
||||
PredictorStream.prototype.readBlockTiff =
|
||||
function predictorStreamReadBlockTiff() {
|
||||
PredictorStream.prototype.readBlockTiff = function predictorStreamReadBlockTiff() {
|
||||
var rowBytes = this.rowBytes;
|
||||
|
||||
var bufferLength = this.bufferLength;
|
||||
@ -746,8 +765,10 @@ var PredictorStream = (function PredictorStreamClosure() {
|
||||
return;
|
||||
}
|
||||
|
||||
var inbuf = 0, outbuf = 0;
|
||||
var inbits = 0, outbits = 0;
|
||||
var inbuf = 0,
|
||||
outbuf = 0;
|
||||
var inbits = 0,
|
||||
outbits = 0;
|
||||
var pos = bufferLength;
|
||||
var i;
|
||||
|
||||
@ -776,46 +797,46 @@ var PredictorStream = (function PredictorStreamClosure() {
|
||||
buffer[pos++] = rawBytes[i];
|
||||
}
|
||||
for (; i < rowBytes; i += 2) {
|
||||
var sum = ((rawBytes[i] & 0xFF) << 8) +
|
||||
(rawBytes[i + 1] & 0xFF) +
|
||||
((buffer[pos - bytesPerPixel] & 0xFF) << 8) +
|
||||
(buffer[pos - bytesPerPixel + 1] & 0xFF);
|
||||
buffer[pos++] = ((sum >> 8) & 0xFF);
|
||||
buffer[pos++] = (sum & 0xFF);
|
||||
var sum =
|
||||
((rawBytes[i] & 0xff) << 8) +
|
||||
(rawBytes[i + 1] & 0xff) +
|
||||
((buffer[pos - bytesPerPixel] & 0xff) << 8) +
|
||||
(buffer[pos - bytesPerPixel + 1] & 0xff);
|
||||
buffer[pos++] = (sum >> 8) & 0xff;
|
||||
buffer[pos++] = sum & 0xff;
|
||||
}
|
||||
} else {
|
||||
var compArray = new Uint8Array(colors + 1);
|
||||
var bitMask = (1 << bits) - 1;
|
||||
var j = 0, k = bufferLength;
|
||||
var j = 0,
|
||||
k = bufferLength;
|
||||
var columns = this.columns;
|
||||
for (i = 0; i < columns; ++i) {
|
||||
for (var kk = 0; kk < colors; ++kk) {
|
||||
if (inbits < bits) {
|
||||
inbuf = (inbuf << 8) | (rawBytes[j++] & 0xFF);
|
||||
inbuf = (inbuf << 8) | (rawBytes[j++] & 0xff);
|
||||
inbits += 8;
|
||||
}
|
||||
compArray[kk] = (compArray[kk] +
|
||||
(inbuf >> (inbits - bits))) & bitMask;
|
||||
compArray[kk] =
|
||||
(compArray[kk] + (inbuf >> (inbits - bits))) & bitMask;
|
||||
inbits -= bits;
|
||||
outbuf = (outbuf << bits) | compArray[kk];
|
||||
outbits += bits;
|
||||
if (outbits >= 8) {
|
||||
buffer[k++] = (outbuf >> (outbits - 8)) & 0xFF;
|
||||
buffer[k++] = (outbuf >> (outbits - 8)) & 0xff;
|
||||
outbits -= 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (outbits > 0) {
|
||||
buffer[k++] = (outbuf << (8 - outbits)) +
|
||||
(inbuf & ((1 << (8 - outbits)) - 1));
|
||||
buffer[k++] =
|
||||
(outbuf << (8 - outbits)) + (inbuf & ((1 << (8 - outbits)) - 1));
|
||||
}
|
||||
}
|
||||
this.bufferLength += rowBytes;
|
||||
};
|
||||
|
||||
PredictorStream.prototype.readBlockPng =
|
||||
function predictorStreamReadBlockPng() {
|
||||
|
||||
PredictorStream.prototype.readBlockPng = function predictorStreamReadBlockPng() {
|
||||
var rowBytes = this.rowBytes;
|
||||
var pixBytes = this.pixBytes;
|
||||
|
||||
@ -834,7 +855,10 @@ var PredictorStream = (function PredictorStreamClosure() {
|
||||
prevRow = new Uint8Array(rowBytes);
|
||||
}
|
||||
|
||||
var i, j = bufferLength, up, c;
|
||||
var i,
|
||||
j = bufferLength,
|
||||
up,
|
||||
c;
|
||||
switch (predictor) {
|
||||
case 0:
|
||||
for (i = 0; i < rowBytes; ++i) {
|
||||
@ -846,13 +870,13 @@ var PredictorStream = (function PredictorStreamClosure() {
|
||||
buffer[j++] = rawBytes[i];
|
||||
}
|
||||
for (; i < rowBytes; ++i) {
|
||||
buffer[j] = (buffer[j - pixBytes] + rawBytes[i]) & 0xFF;
|
||||
buffer[j] = (buffer[j - pixBytes] + rawBytes[i]) & 0xff;
|
||||
j++;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
for (i = 0; i < rowBytes; ++i) {
|
||||
buffer[j++] = (prevRow[i] + rawBytes[i]) & 0xFF;
|
||||
buffer[j++] = (prevRow[i] + rawBytes[i]) & 0xff;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
@ -860,8 +884,8 @@ var PredictorStream = (function PredictorStreamClosure() {
|
||||
buffer[j++] = (prevRow[i] >> 1) + rawBytes[i];
|
||||
}
|
||||
for (; i < rowBytes; ++i) {
|
||||
buffer[j] = (((prevRow[i] + buffer[j - pixBytes]) >> 1) +
|
||||
rawBytes[i]) & 0xFF;
|
||||
buffer[j] =
|
||||
(((prevRow[i] + buffer[j - pixBytes]) >> 1) + rawBytes[i]) & 0xff;
|
||||
j++;
|
||||
}
|
||||
break;
|
||||
@ -945,7 +969,8 @@ var DecryptStream = (function DecryptStreamClosure() {
|
||||
chunk = decrypt(chunk, !hasMoreData);
|
||||
|
||||
var bufferLength = this.bufferLength;
|
||||
var i, n = chunk.length;
|
||||
var i,
|
||||
n = chunk.length;
|
||||
var buffer = this.ensureBuffer(bufferLength + n);
|
||||
for (i = 0; i < n; i++) {
|
||||
buffer[bufferLength++] = chunk[i];
|
||||
@ -973,8 +998,8 @@ var Ascii85Stream = (function Ascii85StreamClosure() {
|
||||
Ascii85Stream.prototype = Object.create(DecodeStream.prototype);
|
||||
|
||||
Ascii85Stream.prototype.readBlock = function Ascii85Stream_readBlock() {
|
||||
var TILDA_CHAR = 0x7E; // '~'
|
||||
var Z_LOWER_CHAR = 0x7A; // 'z'
|
||||
var TILDA_CHAR = 0x7e; // '~'
|
||||
var Z_LOWER_CHAR = 0x7a; // 'z'
|
||||
var EOF = -1;
|
||||
|
||||
var str = this.str;
|
||||
@ -989,7 +1014,8 @@ var Ascii85Stream = (function Ascii85StreamClosure() {
|
||||
return;
|
||||
}
|
||||
|
||||
var bufferLength = this.bufferLength, buffer;
|
||||
var bufferLength = this.bufferLength,
|
||||
buffer;
|
||||
var i;
|
||||
|
||||
// special code for z
|
||||
@ -1030,7 +1056,7 @@ var Ascii85Stream = (function Ascii85StreamClosure() {
|
||||
}
|
||||
|
||||
for (i = 3; i >= 0; --i) {
|
||||
buffer[bufferLength + i] = t & 0xFF;
|
||||
buffer[bufferLength + i] = t & 0xff;
|
||||
t >>= 8;
|
||||
}
|
||||
}
|
||||
@ -1070,17 +1096,21 @@ var AsciiHexStream = (function AsciiHexStreamClosure() {
|
||||
|
||||
var firstDigit = this.firstDigit;
|
||||
for (var i = 0, ii = bytes.length; i < ii; i++) {
|
||||
var ch = bytes[i], digit;
|
||||
if (ch >= 0x30 && ch <= 0x39) { // '0'-'9'
|
||||
digit = ch & 0x0F;
|
||||
} else if ((ch >= 0x41 && ch <= 0x46) || (ch >= 0x61 && ch <= 0x66)) {
|
||||
// 'A'-'Z', 'a'-'z'
|
||||
digit = (ch & 0x0F) + 9;
|
||||
} else if (ch === 0x3E) { // '>'
|
||||
var ch = bytes[i],
|
||||
digit;
|
||||
if (ch >= /* '0' = */ 0x30 && ch <= /* '9' = */ 0x39) {
|
||||
digit = ch & 0x0f;
|
||||
} else if (
|
||||
(ch >= /* 'A' = */ 0x41 && ch <= /* 'Z' = */ 0x46) ||
|
||||
(ch >= /* 'a' = */ 0x61 && ch <= /* 'z' = */ 0x66)
|
||||
) {
|
||||
digit = (ch & 0x0f) + 9;
|
||||
} else if (ch === /* '>' = */ 0x3e) {
|
||||
this.eof = true;
|
||||
break;
|
||||
} else { // probably whitespace
|
||||
continue; // ignoring
|
||||
} else {
|
||||
// Probably whitespace, ignoring.
|
||||
continue;
|
||||
}
|
||||
if (firstDigit < 0) {
|
||||
firstDigit = digit;
|
||||
@ -1091,7 +1121,7 @@ var AsciiHexStream = (function AsciiHexStreamClosure() {
|
||||
}
|
||||
if (firstDigit >= 0 && this.eof) {
|
||||
// incomplete byte
|
||||
buffer[bufferLength++] = (firstDigit << 4);
|
||||
buffer[bufferLength++] = firstDigit << 4;
|
||||
firstDigit = -1;
|
||||
}
|
||||
this.firstDigit = firstDigit;
|
||||
@ -1189,7 +1219,7 @@ var LZWStream = (function LZWStreamClosure() {
|
||||
cachedData = (cachedData << 8) | c;
|
||||
bitsCached += 8;
|
||||
}
|
||||
this.bitsCached = (bitsCached -= n);
|
||||
this.bitsCached = bitsCached -= n;
|
||||
this.cachedData = cachedData;
|
||||
this.lastCode = null;
|
||||
return (cachedData >>> bitsCached) & ((1 << n) - 1);
|
||||
@ -1197,7 +1227,8 @@ var LZWStream = (function LZWStreamClosure() {
|
||||
|
||||
LZWStream.prototype.readBlock = function LZWStream_readBlock() {
|
||||
var blockSize = 512;
|
||||
var estimatedDecodedSize = blockSize * 2, decodedSizeDelta = blockSize;
|
||||
var estimatedDecodedSize = blockSize * 2,
|
||||
decodedSizeDelta = blockSize;
|
||||
var i, j, q;
|
||||
|
||||
var lzwState = this.lzwState;
|
||||
@ -1251,9 +1282,13 @@ var LZWStream = (function LZWStreamClosure() {
|
||||
dictionaryLengths[nextCode] = dictionaryLengths[prevCode] + 1;
|
||||
dictionaryValues[nextCode] = currentSequence[0];
|
||||
nextCode++;
|
||||
codeLength = (nextCode + earlyChange) & (nextCode + earlyChange - 1) ?
|
||||
codeLength : Math.min(Math.log(nextCode + earlyChange) /
|
||||
0.6931471805599453 + 1, 12) | 0;
|
||||
codeLength =
|
||||
(nextCode + earlyChange) & (nextCode + earlyChange - 1)
|
||||
? codeLength
|
||||
: Math.min(
|
||||
Math.log(nextCode + earlyChange) / 0.6931471805599453 + 1,
|
||||
12
|
||||
) | 0;
|
||||
}
|
||||
prevCode = code;
|
||||
|
||||
|
@ -13,9 +13,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { isSpace, warn } from '../shared/util';
|
||||
import { getEncoding } from './encodings';
|
||||
import { Stream } from './stream';
|
||||
import { isSpace, warn } from "../shared/util";
|
||||
import { getEncoding } from "./encodings";
|
||||
import { Stream } from "./stream";
|
||||
|
||||
// Hinting is currently disabled due to unknown problems on windows
|
||||
// in tracemonkey and various other pdfs with type1 fonts.
|
||||
@ -61,21 +61,21 @@ var HINTING_ENABLED = false;
|
||||
*/
|
||||
var Type1CharString = (function Type1CharStringClosure() {
|
||||
var COMMAND_MAP = {
|
||||
'hstem': [1],
|
||||
'vstem': [3],
|
||||
'vmoveto': [4],
|
||||
'rlineto': [5],
|
||||
'hlineto': [6],
|
||||
'vlineto': [7],
|
||||
'rrcurveto': [8],
|
||||
'callsubr': [10],
|
||||
'flex': [12, 35],
|
||||
'drop': [12, 18],
|
||||
'endchar': [14],
|
||||
'rmoveto': [21],
|
||||
'hmoveto': [22],
|
||||
'vhcurveto': [30],
|
||||
'hvcurveto': [31],
|
||||
hstem: [1],
|
||||
vstem: [3],
|
||||
vmoveto: [4],
|
||||
rlineto: [5],
|
||||
hlineto: [6],
|
||||
vlineto: [7],
|
||||
rrcurveto: [8],
|
||||
callsubr: [10],
|
||||
flex: [12, 35],
|
||||
drop: [12, 18],
|
||||
endchar: [14],
|
||||
rmoveto: [21],
|
||||
hmoveto: [22],
|
||||
vhcurveto: [30],
|
||||
hvcurveto: [31],
|
||||
};
|
||||
|
||||
function Type1CharString() {
|
||||
@ -87,8 +87,11 @@ var Type1CharString = (function Type1CharStringClosure() {
|
||||
}
|
||||
|
||||
Type1CharString.prototype = {
|
||||
convert: function Type1CharString_convert(encoded, subrs,
|
||||
seacAnalysisEnabled) {
|
||||
convert: function Type1CharString_convert(
|
||||
encoded,
|
||||
subrs,
|
||||
seacAnalysisEnabled
|
||||
) {
|
||||
var count = encoded.length;
|
||||
var error = false;
|
||||
var wx, sbx, subrNumber;
|
||||
@ -154,8 +157,11 @@ var Type1CharString = (function Type1CharStringClosure() {
|
||||
error = true;
|
||||
break;
|
||||
}
|
||||
error = this.convert(subrs[subrNumber], subrs,
|
||||
seacAnalysisEnabled);
|
||||
error = this.convert(
|
||||
subrs[subrNumber],
|
||||
subrs,
|
||||
seacAnalysisEnabled
|
||||
);
|
||||
break;
|
||||
case 11: // return
|
||||
return error;
|
||||
@ -214,7 +220,7 @@ var Type1CharString = (function Type1CharStringClosure() {
|
||||
break;
|
||||
case (12 << 8) + 2: // hstem3
|
||||
if (!HINTING_ENABLED) {
|
||||
this.stack = [];
|
||||
this.stack = [];
|
||||
break;
|
||||
}
|
||||
// See vstem3.
|
||||
@ -308,12 +314,15 @@ var Type1CharString = (function Type1CharStringClosure() {
|
||||
} else if (value <= 246) {
|
||||
value = value - 139;
|
||||
} else if (value <= 250) {
|
||||
value = ((value - 247) * 256) + encoded[++i] + 108;
|
||||
value = (value - 247) * 256 + encoded[++i] + 108;
|
||||
} else if (value <= 254) {
|
||||
value = -((value - 251) * 256) - encoded[++i] - 108;
|
||||
} else {
|
||||
value = (encoded[++i] & 0xff) << 24 | (encoded[++i] & 0xff) << 16 |
|
||||
(encoded[++i] & 0xff) << 8 | (encoded[++i] & 0xff) << 0;
|
||||
value =
|
||||
((encoded[++i] & 0xff) << 24) |
|
||||
((encoded[++i] & 0xff) << 16) |
|
||||
((encoded[++i] & 0xff) << 8) |
|
||||
((encoded[++i] & 0xff) << 0);
|
||||
}
|
||||
this.stack.push(value);
|
||||
}
|
||||
@ -330,13 +339,16 @@ var Type1CharString = (function Type1CharStringClosure() {
|
||||
var value = this.stack[i];
|
||||
if (Number.isInteger(value)) {
|
||||
this.output.push(28, (value >> 8) & 0xff, value & 0xff);
|
||||
} else { // fixed point
|
||||
} else {
|
||||
// fixed point
|
||||
value = (65536 * value) | 0;
|
||||
this.output.push(255,
|
||||
(value >> 24) & 0xFF,
|
||||
(value >> 16) & 0xFF,
|
||||
(value >> 8) & 0xFF,
|
||||
value & 0xFF);
|
||||
this.output.push(
|
||||
255,
|
||||
(value >> 24) & 0xff,
|
||||
(value >> 16) & 0xff,
|
||||
(value >> 8) & 0xff,
|
||||
value & 0xff
|
||||
);
|
||||
}
|
||||
}
|
||||
this.output.push.apply(this.output, command);
|
||||
@ -370,16 +382,22 @@ var Type1Parser = (function Type1ParserClosure() {
|
||||
var CHAR_STRS_ENCRYPT_KEY = 4330;
|
||||
|
||||
function isHexDigit(code) {
|
||||
return code >= 48 && code <= 57 || // '0'-'9'
|
||||
code >= 65 && code <= 70 || // 'A'-'F'
|
||||
code >= 97 && code <= 102; // 'a'-'f'
|
||||
return (
|
||||
(code >= 48 && code <= 57) || // '0'-'9'
|
||||
(code >= 65 && code <= 70) || // 'A'-'F'
|
||||
(code >= 97 && code <= 102) // 'a'-'f'
|
||||
);
|
||||
}
|
||||
|
||||
function decrypt(data, key, discardNumber) {
|
||||
if (discardNumber >= data.length) {
|
||||
return new Uint8Array(0);
|
||||
}
|
||||
var r = key | 0, c1 = 52845, c2 = 22719, i, j;
|
||||
var r = key | 0,
|
||||
c1 = 52845,
|
||||
c2 = 22719,
|
||||
i,
|
||||
j;
|
||||
for (i = 0; i < discardNumber; i++) {
|
||||
r = ((data[i] + r) * c1 + c2) & ((1 << 16) - 1);
|
||||
}
|
||||
@ -394,8 +412,11 @@ var Type1Parser = (function Type1ParserClosure() {
|
||||
}
|
||||
|
||||
function decryptAscii(data, key, discardNumber) {
|
||||
var r = key | 0, c1 = 52845, c2 = 22719;
|
||||
var count = data.length, maybeLength = count >>> 1;
|
||||
var r = key | 0,
|
||||
c1 = 52845,
|
||||
c2 = 22719;
|
||||
var count = data.length,
|
||||
maybeLength = count >>> 1;
|
||||
var decrypted = new Uint8Array(maybeLength);
|
||||
var i, j;
|
||||
for (i = 0, j = 0; i < count; i++) {
|
||||
@ -405,7 +426,7 @@ var Type1Parser = (function Type1ParserClosure() {
|
||||
}
|
||||
i++;
|
||||
var digit2;
|
||||
while (i < count && !isHexDigit(digit2 = data[i])) {
|
||||
while (i < count && !isHexDigit((digit2 = data[i]))) {
|
||||
i++;
|
||||
}
|
||||
if (i < count) {
|
||||
@ -418,19 +439,31 @@ var Type1Parser = (function Type1ParserClosure() {
|
||||
}
|
||||
|
||||
function isSpecial(c) {
|
||||
return c === 0x2F || // '/'
|
||||
c === 0x5B || c === 0x5D || // '[', ']'
|
||||
c === 0x7B || c === 0x7D || // '{', '}'
|
||||
c === 0x28 || c === 0x29; // '(', ')'
|
||||
return (
|
||||
c === 0x2f || // '/'
|
||||
c === 0x5b ||
|
||||
c === 0x5d || // '[', ']'
|
||||
c === 0x7b ||
|
||||
c === 0x7d || // '{', '}'
|
||||
c === 0x28 ||
|
||||
c === 0x29
|
||||
); // '(', ')'
|
||||
}
|
||||
|
||||
function Type1Parser(stream, encrypted, seacAnalysisEnabled) {
|
||||
if (encrypted) {
|
||||
var data = stream.getBytes();
|
||||
var isBinary = !(isHexDigit(data[0]) && isHexDigit(data[1]) &&
|
||||
isHexDigit(data[2]) && isHexDigit(data[3]));
|
||||
stream = new Stream(isBinary ? decrypt(data, EEXEC_ENCRYPT_KEY, 4) :
|
||||
decryptAscii(data, EEXEC_ENCRYPT_KEY, 4));
|
||||
var isBinary = !(
|
||||
isHexDigit(data[0]) &&
|
||||
isHexDigit(data[1]) &&
|
||||
isHexDigit(data[2]) &&
|
||||
isHexDigit(data[3])
|
||||
);
|
||||
stream = new Stream(
|
||||
isBinary
|
||||
? decrypt(data, EEXEC_ENCRYPT_KEY, 4)
|
||||
: decryptAscii(data, EEXEC_ENCRYPT_KEY, 4)
|
||||
);
|
||||
}
|
||||
this.seacAnalysisEnabled = !!seacAnalysisEnabled;
|
||||
|
||||
@ -444,7 +477,7 @@ var Type1Parser = (function Type1ParserClosure() {
|
||||
var array = [];
|
||||
while (true) {
|
||||
var token = this.getToken();
|
||||
if (token === null || token === ']' || token === '}') {
|
||||
if (token === null || token === "]" || token === "}") {
|
||||
break;
|
||||
}
|
||||
array.push(parseFloat(token || 0));
|
||||
@ -468,7 +501,7 @@ var Type1Parser = (function Type1ParserClosure() {
|
||||
var token = this.getToken();
|
||||
|
||||
// Use 1 and 0 since that's what type2 charstrings use.
|
||||
return token === 'true' ? 1 : 0;
|
||||
return token === "true" ? 1 : 0;
|
||||
},
|
||||
|
||||
nextChar: function Type1_nextChar() {
|
||||
@ -485,10 +518,10 @@ var Type1Parser = (function Type1ParserClosure() {
|
||||
}
|
||||
|
||||
if (comment) {
|
||||
if (ch === 0x0A || ch === 0x0D) {
|
||||
if (ch === 0x0a || ch === 0x0d) {
|
||||
comment = false;
|
||||
}
|
||||
} else if (ch === 0x25) { // '%'
|
||||
} else if (ch === /* '%' = */ 0x25) {
|
||||
comment = true;
|
||||
} else if (!isSpace(ch)) {
|
||||
break;
|
||||
@ -499,7 +532,7 @@ var Type1Parser = (function Type1ParserClosure() {
|
||||
this.nextChar();
|
||||
return String.fromCharCode(ch);
|
||||
}
|
||||
var token = '';
|
||||
var token = "";
|
||||
do {
|
||||
token += String.fromCharCode(ch);
|
||||
ch = this.nextChar();
|
||||
@ -523,24 +556,25 @@ var Type1Parser = (function Type1ParserClosure() {
|
||||
extractFontProgram: function Type1Parser_extractFontProgram(properties) {
|
||||
var stream = this.stream;
|
||||
|
||||
var subrs = [], charstrings = [];
|
||||
var subrs = [],
|
||||
charstrings = [];
|
||||
var privateData = Object.create(null);
|
||||
privateData['lenIV'] = 4;
|
||||
privateData["lenIV"] = 4;
|
||||
var program = {
|
||||
subrs: [],
|
||||
charstrings: [],
|
||||
properties: {
|
||||
'privateData': privateData,
|
||||
privateData,
|
||||
},
|
||||
};
|
||||
var token, length, data, lenIV, encoded;
|
||||
while ((token = this.getToken()) !== null) {
|
||||
if (token !== '/') {
|
||||
if (token !== "/") {
|
||||
continue;
|
||||
}
|
||||
token = this.getToken();
|
||||
switch (token) {
|
||||
case 'CharStrings':
|
||||
case "CharStrings":
|
||||
// The number immediately following CharStrings must be greater or
|
||||
// equal to the number of CharStrings.
|
||||
this.getToken();
|
||||
@ -549,22 +583,22 @@ var Type1Parser = (function Type1ParserClosure() {
|
||||
this.getToken(); // read in 'begin'
|
||||
while (true) {
|
||||
token = this.getToken();
|
||||
if (token === null || token === 'end') {
|
||||
if (token === null || token === "end") {
|
||||
break;
|
||||
}
|
||||
|
||||
if (token !== '/') {
|
||||
if (token !== "/") {
|
||||
continue;
|
||||
}
|
||||
var glyph = this.getToken();
|
||||
length = this.readInt();
|
||||
this.getToken(); // read in 'RD' or '-|'
|
||||
data = (length > 0 ? stream.getBytes(length) : new Uint8Array(0));
|
||||
lenIV = program.properties.privateData['lenIV'];
|
||||
data = length > 0 ? stream.getBytes(length) : new Uint8Array(0);
|
||||
lenIV = program.properties.privateData["lenIV"];
|
||||
encoded = this.readCharStrings(data, lenIV);
|
||||
this.nextChar();
|
||||
token = this.getToken(); // read in 'ND' or '|-'
|
||||
if (token === 'noaccess') {
|
||||
if (token === "noaccess") {
|
||||
this.getToken(); // read in 'def'
|
||||
}
|
||||
charstrings.push({
|
||||
@ -573,54 +607,56 @@ var Type1Parser = (function Type1ParserClosure() {
|
||||
});
|
||||
}
|
||||
break;
|
||||
case 'Subrs':
|
||||
case "Subrs":
|
||||
this.readInt(); // num
|
||||
this.getToken(); // read in 'array'
|
||||
while (this.getToken() === 'dup') {
|
||||
while (this.getToken() === "dup") {
|
||||
var index = this.readInt();
|
||||
length = this.readInt();
|
||||
this.getToken(); // read in 'RD' or '-|'
|
||||
data = (length > 0 ? stream.getBytes(length) : new Uint8Array(0));
|
||||
lenIV = program.properties.privateData['lenIV'];
|
||||
data = length > 0 ? stream.getBytes(length) : new Uint8Array(0);
|
||||
lenIV = program.properties.privateData["lenIV"];
|
||||
encoded = this.readCharStrings(data, lenIV);
|
||||
this.nextChar();
|
||||
token = this.getToken(); // read in 'NP' or '|'
|
||||
if (token === 'noaccess') {
|
||||
if (token === "noaccess") {
|
||||
this.getToken(); // read in 'put'
|
||||
}
|
||||
subrs[index] = encoded;
|
||||
}
|
||||
break;
|
||||
case 'BlueValues':
|
||||
case 'OtherBlues':
|
||||
case 'FamilyBlues':
|
||||
case 'FamilyOtherBlues':
|
||||
case "BlueValues":
|
||||
case "OtherBlues":
|
||||
case "FamilyBlues":
|
||||
case "FamilyOtherBlues":
|
||||
var blueArray = this.readNumberArray();
|
||||
// *Blue* values may contain invalid data: disables reading of
|
||||
// those values when hinting is disabled.
|
||||
if (blueArray.length > 0 && (blueArray.length % 2) === 0 &&
|
||||
HINTING_ENABLED) {
|
||||
if (
|
||||
blueArray.length > 0 &&
|
||||
blueArray.length % 2 === 0 &&
|
||||
HINTING_ENABLED
|
||||
) {
|
||||
program.properties.privateData[token] = blueArray;
|
||||
}
|
||||
break;
|
||||
case 'StemSnapH':
|
||||
case 'StemSnapV':
|
||||
case "StemSnapH":
|
||||
case "StemSnapV":
|
||||
program.properties.privateData[token] = this.readNumberArray();
|
||||
break;
|
||||
case 'StdHW':
|
||||
case 'StdVW':
|
||||
program.properties.privateData[token] =
|
||||
this.readNumberArray()[0];
|
||||
case "StdHW":
|
||||
case "StdVW":
|
||||
program.properties.privateData[token] = this.readNumberArray()[0];
|
||||
break;
|
||||
case 'BlueShift':
|
||||
case 'lenIV':
|
||||
case 'BlueFuzz':
|
||||
case 'BlueScale':
|
||||
case 'LanguageGroup':
|
||||
case 'ExpansionFactor':
|
||||
case "BlueShift":
|
||||
case "lenIV":
|
||||
case "BlueFuzz":
|
||||
case "BlueScale":
|
||||
case "LanguageGroup":
|
||||
case "ExpansionFactor":
|
||||
program.properties.privateData[token] = this.readNumber();
|
||||
break;
|
||||
case 'ForceBold':
|
||||
case "ForceBold":
|
||||
program.properties.privateData[token] = this.readBoolean();
|
||||
break;
|
||||
}
|
||||
@ -630,8 +666,11 @@ var Type1Parser = (function Type1ParserClosure() {
|
||||
glyph = charstrings[i].glyph;
|
||||
encoded = charstrings[i].encoded;
|
||||
var charString = new Type1CharString();
|
||||
var error = charString.convert(encoded, subrs,
|
||||
this.seacAnalysisEnabled);
|
||||
var error = charString.convert(
|
||||
encoded,
|
||||
subrs,
|
||||
this.seacAnalysisEnabled
|
||||
);
|
||||
var output = charString.output;
|
||||
if (error) {
|
||||
// It seems when FreeType encounters an error while evaluating a glyph
|
||||
@ -651,8 +690,12 @@ var Type1Parser = (function Type1ParserClosure() {
|
||||
// entry, with ones from the font data (fixes issue11150_reduced.pdf).
|
||||
if (properties.builtInEncoding) {
|
||||
const index = properties.builtInEncoding.indexOf(glyph);
|
||||
if (index > -1 && properties.widths[index] === undefined &&
|
||||
index >= properties.firstChar && index <= properties.lastChar) {
|
||||
if (
|
||||
index > -1 &&
|
||||
properties.widths[index] === undefined &&
|
||||
index >= properties.firstChar &&
|
||||
index <= properties.lastChar
|
||||
) {
|
||||
properties.widths[index] = charString.width;
|
||||
}
|
||||
}
|
||||
@ -664,16 +707,16 @@ var Type1Parser = (function Type1ParserClosure() {
|
||||
extractFontHeader: function Type1Parser_extractFontHeader(properties) {
|
||||
var token;
|
||||
while ((token = this.getToken()) !== null) {
|
||||
if (token !== '/') {
|
||||
if (token !== "/") {
|
||||
continue;
|
||||
}
|
||||
token = this.getToken();
|
||||
switch (token) {
|
||||
case 'FontMatrix':
|
||||
case "FontMatrix":
|
||||
var matrix = this.readNumberArray();
|
||||
properties.fontMatrix = matrix;
|
||||
break;
|
||||
case 'Encoding':
|
||||
case "Encoding":
|
||||
var encodingArg = this.getToken();
|
||||
var encoding;
|
||||
if (!/^\d+$/.test(encodingArg)) {
|
||||
@ -687,13 +730,13 @@ var Type1Parser = (function Type1ParserClosure() {
|
||||
for (var j = 0; j < size; j++) {
|
||||
token = this.getToken();
|
||||
// skipping till first dup or def (e.g. ignoring for statement)
|
||||
while (token !== 'dup' && token !== 'def') {
|
||||
while (token !== "dup" && token !== "def") {
|
||||
token = this.getToken();
|
||||
if (token === null) {
|
||||
return; // invalid header
|
||||
}
|
||||
}
|
||||
if (token === 'def') {
|
||||
if (token === "def") {
|
||||
break; // read all array data
|
||||
}
|
||||
var index = this.readInt();
|
||||
@ -705,7 +748,7 @@ var Type1Parser = (function Type1ParserClosure() {
|
||||
}
|
||||
properties.builtInEncoding = encoding;
|
||||
break;
|
||||
case 'FontBBox':
|
||||
case "FontBBox":
|
||||
var fontBBox = this.readNumberArray();
|
||||
// adjusting ascent/descent
|
||||
properties.ascent = Math.max(fontBBox[3], fontBBox[1]);
|
||||
@ -720,6 +763,4 @@ var Type1Parser = (function Type1ParserClosure() {
|
||||
return Type1Parser;
|
||||
})();
|
||||
|
||||
export {
|
||||
Type1Parser,
|
||||
};
|
||||
export { Type1Parser };
|
||||
|
3074
src/core/unicode.js
3074
src/core/unicode.js
File diff suppressed because it is too large
Load Diff
@ -14,17 +14,28 @@
|
||||
*/
|
||||
|
||||
import {
|
||||
AbortException, arrayByteLength, arraysToBytes, createPromiseCapability,
|
||||
getVerbosityLevel, info, InvalidPDFException, MissingPDFException,
|
||||
PasswordException, setVerbosityLevel, UnexpectedResponseException,
|
||||
UnknownErrorException, UNSUPPORTED_FEATURES, VerbosityLevel, warn
|
||||
} from '../shared/util';
|
||||
import { clearPrimitiveCaches, Ref } from './primitives';
|
||||
import { LocalPdfManager, NetworkPdfManager } from './pdf_manager';
|
||||
import { isNodeJS } from '../shared/is_node';
|
||||
import { MessageHandler } from '../shared/message_handler';
|
||||
import { PDFWorkerStream } from './worker_stream';
|
||||
import { XRefParseException } from './core_utils';
|
||||
AbortException,
|
||||
arrayByteLength,
|
||||
arraysToBytes,
|
||||
createPromiseCapability,
|
||||
getVerbosityLevel,
|
||||
info,
|
||||
InvalidPDFException,
|
||||
MissingPDFException,
|
||||
PasswordException,
|
||||
setVerbosityLevel,
|
||||
UnexpectedResponseException,
|
||||
UnknownErrorException,
|
||||
UNSUPPORTED_FEATURES,
|
||||
VerbosityLevel,
|
||||
warn,
|
||||
} from "../shared/util";
|
||||
import { clearPrimitiveCaches, Ref } from "./primitives";
|
||||
import { LocalPdfManager, NetworkPdfManager } from "./pdf_manager";
|
||||
import { isNodeJS } from "../shared/is_node";
|
||||
import { MessageHandler } from "../shared/message_handler";
|
||||
import { PDFWorkerStream } from "./worker_stream";
|
||||
import { XRefParseException } from "./core_utils";
|
||||
|
||||
var WorkerTask = (function WorkerTaskClosure() {
|
||||
function WorkerTask(name) {
|
||||
@ -48,7 +59,7 @@ var WorkerTask = (function WorkerTaskClosure() {
|
||||
|
||||
ensureNotTerminated() {
|
||||
if (this.terminated) {
|
||||
throw new Error('Worker task was terminated');
|
||||
throw new Error("Worker task was terminated");
|
||||
}
|
||||
},
|
||||
};
|
||||
@ -59,7 +70,7 @@ var WorkerTask = (function WorkerTaskClosure() {
|
||||
var WorkerMessageHandler = {
|
||||
setup(handler, port) {
|
||||
var testMessageProcessed = false;
|
||||
handler.on('test', function wphSetupTest(data) {
|
||||
handler.on("test", function wphSetupTest(data) {
|
||||
if (testMessageProcessed) {
|
||||
return; // we already processed 'test' message once
|
||||
}
|
||||
@ -67,21 +78,21 @@ var WorkerMessageHandler = {
|
||||
|
||||
// check if Uint8Array can be sent to worker
|
||||
if (!(data instanceof Uint8Array)) {
|
||||
handler.send('test', null);
|
||||
handler.send("test", null);
|
||||
return;
|
||||
}
|
||||
// making sure postMessage transfers are working
|
||||
const supportTransfers = data[0] === 255;
|
||||
handler.postMessageTransfers = supportTransfers;
|
||||
|
||||
handler.send('test', { supportTransfers, });
|
||||
handler.send("test", { supportTransfers });
|
||||
});
|
||||
|
||||
handler.on('configure', function wphConfigure(data) {
|
||||
handler.on("configure", function wphConfigure(data) {
|
||||
setVerbosityLevel(data.verbosity);
|
||||
});
|
||||
|
||||
handler.on('GetDocRequest', function wphSetupDoc(data) {
|
||||
handler.on("GetDocRequest", function wphSetupDoc(data) {
|
||||
return WorkerMessageHandler.createDocumentHandler(data, port);
|
||||
});
|
||||
},
|
||||
@ -96,16 +107,19 @@ var WorkerMessageHandler = {
|
||||
|
||||
const apiVersion = docParams.apiVersion;
|
||||
const workerVersion =
|
||||
typeof PDFJSDev !== 'undefined' && !PDFJSDev.test('TESTING') ?
|
||||
PDFJSDev.eval('BUNDLE_VERSION') : null;
|
||||
typeof PDFJSDev !== "undefined" && !PDFJSDev.test("TESTING")
|
||||
? PDFJSDev.eval("BUNDLE_VERSION")
|
||||
: null;
|
||||
if (apiVersion !== workerVersion) {
|
||||
throw new Error(`The API version "${apiVersion}" does not match ` +
|
||||
`the Worker version "${workerVersion}".`);
|
||||
throw new Error(
|
||||
`The API version "${apiVersion}" does not match ` +
|
||||
`the Worker version "${workerVersion}".`
|
||||
);
|
||||
}
|
||||
|
||||
var docId = docParams.docId;
|
||||
var docBaseUrl = docParams.docBaseUrl;
|
||||
var workerHandlerName = docParams.docId + '_worker';
|
||||
var workerHandlerName = docParams.docId + "_worker";
|
||||
var handler = new MessageHandler(workerHandlerName, docId, port);
|
||||
|
||||
// Ensure that postMessage transfers are always correctly enabled/disabled,
|
||||
@ -114,7 +128,7 @@ var WorkerMessageHandler = {
|
||||
|
||||
function ensureNotTerminated() {
|
||||
if (terminated) {
|
||||
throw new Error('Worker was terminated');
|
||||
throw new Error("Worker was terminated");
|
||||
}
|
||||
}
|
||||
|
||||
@ -129,21 +143,21 @@ var WorkerMessageHandler = {
|
||||
}
|
||||
|
||||
async function loadDocument(recoveryMode) {
|
||||
await pdfManager.ensureDoc('checkHeader');
|
||||
await pdfManager.ensureDoc('parseStartXRef');
|
||||
await pdfManager.ensureDoc('parse', [recoveryMode]);
|
||||
await pdfManager.ensureDoc("checkHeader");
|
||||
await pdfManager.ensureDoc("parseStartXRef");
|
||||
await pdfManager.ensureDoc("parse", [recoveryMode]);
|
||||
|
||||
if (!recoveryMode) {
|
||||
// Check that at least the first page can be successfully loaded,
|
||||
// since otherwise the XRef table is definitely not valid.
|
||||
await pdfManager.ensureDoc('checkFirstPage');
|
||||
await pdfManager.ensureDoc("checkFirstPage");
|
||||
}
|
||||
|
||||
const [numPages, fingerprint] = await Promise.all([
|
||||
pdfManager.ensureDoc('numPages'),
|
||||
pdfManager.ensureDoc('fingerprint'),
|
||||
pdfManager.ensureDoc("numPages"),
|
||||
pdfManager.ensureDoc("fingerprint"),
|
||||
]);
|
||||
return { numPages, fingerprint, };
|
||||
return { numPages, fingerprint };
|
||||
}
|
||||
|
||||
function getPdfManager(data, evaluatorOptions) {
|
||||
@ -153,8 +167,13 @@ var WorkerMessageHandler = {
|
||||
var source = data.source;
|
||||
if (source.data) {
|
||||
try {
|
||||
pdfManager = new LocalPdfManager(docId, source.data, source.password,
|
||||
evaluatorOptions, docBaseUrl);
|
||||
pdfManager = new LocalPdfManager(
|
||||
docId,
|
||||
source.data,
|
||||
source.password,
|
||||
evaluatorOptions,
|
||||
docBaseUrl
|
||||
);
|
||||
pdfManagerCapability.resolve(pdfManager);
|
||||
} catch (ex) {
|
||||
pdfManagerCapability.reject(ex);
|
||||
@ -162,7 +181,8 @@ var WorkerMessageHandler = {
|
||||
return pdfManagerCapability.promise;
|
||||
}
|
||||
|
||||
var pdfStream, cachedChunks = [];
|
||||
var pdfStream,
|
||||
cachedChunks = [];
|
||||
try {
|
||||
pdfStream = new PDFWorkerStream(handler);
|
||||
} catch (ex) {
|
||||
@ -171,55 +191,68 @@ var WorkerMessageHandler = {
|
||||
}
|
||||
|
||||
var fullRequest = pdfStream.getFullReader();
|
||||
fullRequest.headersReady.then(function () {
|
||||
if (!fullRequest.isRangeSupported) {
|
||||
return;
|
||||
}
|
||||
fullRequest.headersReady
|
||||
.then(function() {
|
||||
if (!fullRequest.isRangeSupported) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We don't need auto-fetch when streaming is enabled.
|
||||
var disableAutoFetch = source.disableAutoFetch ||
|
||||
fullRequest.isStreamingSupported;
|
||||
pdfManager = new NetworkPdfManager(docId, pdfStream, {
|
||||
msgHandler: handler,
|
||||
password: source.password,
|
||||
length: fullRequest.contentLength,
|
||||
disableAutoFetch,
|
||||
rangeChunkSize: source.rangeChunkSize,
|
||||
}, evaluatorOptions, docBaseUrl);
|
||||
// There may be a chance that `pdfManager` is not initialized
|
||||
// for first few runs of `readchunk` block of code. Be sure
|
||||
// to send all cached chunks, if any, to chunked_stream via
|
||||
// pdf_manager.
|
||||
for (let i = 0; i < cachedChunks.length; i++) {
|
||||
pdfManager.sendProgressiveData(cachedChunks[i]);
|
||||
}
|
||||
// We don't need auto-fetch when streaming is enabled.
|
||||
var disableAutoFetch =
|
||||
source.disableAutoFetch || fullRequest.isStreamingSupported;
|
||||
pdfManager = new NetworkPdfManager(
|
||||
docId,
|
||||
pdfStream,
|
||||
{
|
||||
msgHandler: handler,
|
||||
password: source.password,
|
||||
length: fullRequest.contentLength,
|
||||
disableAutoFetch,
|
||||
rangeChunkSize: source.rangeChunkSize,
|
||||
},
|
||||
evaluatorOptions,
|
||||
docBaseUrl
|
||||
);
|
||||
// There may be a chance that `pdfManager` is not initialized
|
||||
// for first few runs of `readchunk` block of code. Be sure
|
||||
// to send all cached chunks, if any, to chunked_stream via
|
||||
// pdf_manager.
|
||||
for (let i = 0; i < cachedChunks.length; i++) {
|
||||
pdfManager.sendProgressiveData(cachedChunks[i]);
|
||||
}
|
||||
|
||||
cachedChunks = [];
|
||||
pdfManagerCapability.resolve(pdfManager);
|
||||
cancelXHRs = null;
|
||||
}).catch(function (reason) {
|
||||
pdfManagerCapability.reject(reason);
|
||||
cancelXHRs = null;
|
||||
});
|
||||
cachedChunks = [];
|
||||
pdfManagerCapability.resolve(pdfManager);
|
||||
cancelXHRs = null;
|
||||
})
|
||||
.catch(function(reason) {
|
||||
pdfManagerCapability.reject(reason);
|
||||
cancelXHRs = null;
|
||||
});
|
||||
|
||||
var loaded = 0;
|
||||
var flushChunks = function () {
|
||||
var flushChunks = function() {
|
||||
var pdfFile = arraysToBytes(cachedChunks);
|
||||
if (source.length && pdfFile.length !== source.length) {
|
||||
warn('reported HTTP length is different from actual');
|
||||
warn("reported HTTP length is different from actual");
|
||||
}
|
||||
// the data is array, instantiating directly from it
|
||||
try {
|
||||
pdfManager = new LocalPdfManager(docId, pdfFile, source.password,
|
||||
evaluatorOptions, docBaseUrl);
|
||||
pdfManager = new LocalPdfManager(
|
||||
docId,
|
||||
pdfFile,
|
||||
source.password,
|
||||
evaluatorOptions,
|
||||
docBaseUrl
|
||||
);
|
||||
pdfManagerCapability.resolve(pdfManager);
|
||||
} catch (ex) {
|
||||
pdfManagerCapability.reject(ex);
|
||||
}
|
||||
cachedChunks = [];
|
||||
};
|
||||
var readPromise = new Promise(function (resolve, reject) {
|
||||
var readChunk = function (chunk) {
|
||||
var readPromise = new Promise(function(resolve, reject) {
|
||||
var readChunk = function(chunk) {
|
||||
try {
|
||||
ensureNotTerminated();
|
||||
if (chunk.done) {
|
||||
@ -233,7 +266,7 @@ var WorkerMessageHandler = {
|
||||
var data = chunk.value;
|
||||
loaded += arrayByteLength(data);
|
||||
if (!fullRequest.isStreamingSupported) {
|
||||
handler.send('DocProgress', {
|
||||
handler.send("DocProgress", {
|
||||
loaded,
|
||||
total: Math.max(loaded, fullRequest.contentLength || 0),
|
||||
});
|
||||
@ -252,7 +285,7 @@ var WorkerMessageHandler = {
|
||||
};
|
||||
fullRequest.read().then(readChunk, reject);
|
||||
});
|
||||
readPromise.catch(function (e) {
|
||||
readPromise.catch(function(e) {
|
||||
pdfManagerCapability.reject(e);
|
||||
cancelXHRs = null;
|
||||
});
|
||||
@ -267,7 +300,7 @@ var WorkerMessageHandler = {
|
||||
function setupDoc(data) {
|
||||
function onSuccess(doc) {
|
||||
ensureNotTerminated();
|
||||
handler.send('GetDoc', { pdfInfo: doc, });
|
||||
handler.send("GetDoc", { pdfInfo: doc });
|
||||
}
|
||||
|
||||
function onFailure(ex) {
|
||||
@ -277,43 +310,54 @@ var WorkerMessageHandler = {
|
||||
var task = new WorkerTask(`PasswordException: response ${ex.code}`);
|
||||
startWorkerTask(task);
|
||||
|
||||
handler.sendWithPromise('PasswordRequest', ex).then(function(data) {
|
||||
finishWorkerTask(task);
|
||||
pdfManager.updatePassword(data.password);
|
||||
pdfManagerReady();
|
||||
}).catch(function() {
|
||||
finishWorkerTask(task);
|
||||
handler.send('DocException', ex);
|
||||
});
|
||||
} else if (ex instanceof InvalidPDFException ||
|
||||
ex instanceof MissingPDFException ||
|
||||
ex instanceof UnexpectedResponseException ||
|
||||
ex instanceof UnknownErrorException) {
|
||||
handler.send('DocException', ex);
|
||||
handler
|
||||
.sendWithPromise("PasswordRequest", ex)
|
||||
.then(function(data) {
|
||||
finishWorkerTask(task);
|
||||
pdfManager.updatePassword(data.password);
|
||||
pdfManagerReady();
|
||||
})
|
||||
.catch(function() {
|
||||
finishWorkerTask(task);
|
||||
handler.send("DocException", ex);
|
||||
});
|
||||
} else if (
|
||||
ex instanceof InvalidPDFException ||
|
||||
ex instanceof MissingPDFException ||
|
||||
ex instanceof UnexpectedResponseException ||
|
||||
ex instanceof UnknownErrorException
|
||||
) {
|
||||
handler.send("DocException", ex);
|
||||
} else {
|
||||
handler.send('DocException',
|
||||
new UnknownErrorException(ex.message, ex.toString()));
|
||||
handler.send(
|
||||
"DocException",
|
||||
new UnknownErrorException(ex.message, ex.toString())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function pdfManagerReady() {
|
||||
ensureNotTerminated();
|
||||
|
||||
loadDocument(false).then(onSuccess, function loadFailure(ex) {
|
||||
ensureNotTerminated();
|
||||
|
||||
// Try again with recoveryMode == true
|
||||
if (!(ex instanceof XRefParseException)) {
|
||||
onFailure(ex);
|
||||
return;
|
||||
}
|
||||
pdfManager.requestLoadedStream();
|
||||
pdfManager.onLoadedStream().then(function() {
|
||||
loadDocument(false).then(
|
||||
onSuccess,
|
||||
function loadFailure(ex) {
|
||||
ensureNotTerminated();
|
||||
|
||||
loadDocument(true).then(onSuccess, onFailure);
|
||||
});
|
||||
}, onFailure);
|
||||
// Try again with recoveryMode == true
|
||||
if (!(ex instanceof XRefParseException)) {
|
||||
onFailure(ex);
|
||||
return;
|
||||
}
|
||||
pdfManager.requestLoadedStream();
|
||||
pdfManager.onLoadedStream().then(function() {
|
||||
ensureNotTerminated();
|
||||
|
||||
loadDocument(true).then(onSuccess, onFailure);
|
||||
});
|
||||
},
|
||||
onFailure
|
||||
);
|
||||
}
|
||||
|
||||
ensureNotTerminated();
|
||||
@ -327,28 +371,32 @@ var WorkerMessageHandler = {
|
||||
isEvalSupported: data.isEvalSupported,
|
||||
};
|
||||
|
||||
getPdfManager(data, evaluatorOptions).then(function (newPdfManager) {
|
||||
if (terminated) {
|
||||
// We were in a process of setting up the manager, but it got
|
||||
// terminated in the middle.
|
||||
newPdfManager.terminate(new AbortException('Worker was terminated.'));
|
||||
throw new Error('Worker was terminated');
|
||||
}
|
||||
pdfManager = newPdfManager;
|
||||
getPdfManager(data, evaluatorOptions)
|
||||
.then(function(newPdfManager) {
|
||||
if (terminated) {
|
||||
// We were in a process of setting up the manager, but it got
|
||||
// terminated in the middle.
|
||||
newPdfManager.terminate(
|
||||
new AbortException("Worker was terminated.")
|
||||
);
|
||||
throw new Error("Worker was terminated");
|
||||
}
|
||||
pdfManager = newPdfManager;
|
||||
|
||||
pdfManager.onLoadedStream().then(function(stream) {
|
||||
handler.send('DataLoaded', { length: stream.bytes.byteLength, });
|
||||
});
|
||||
}).then(pdfManagerReady, onFailure);
|
||||
pdfManager.onLoadedStream().then(function(stream) {
|
||||
handler.send("DataLoaded", { length: stream.bytes.byteLength });
|
||||
});
|
||||
})
|
||||
.then(pdfManagerReady, onFailure);
|
||||
}
|
||||
|
||||
handler.on('GetPage', function wphSetupGetPage(data) {
|
||||
handler.on("GetPage", function wphSetupGetPage(data) {
|
||||
return pdfManager.getPage(data.pageIndex).then(function(page) {
|
||||
return Promise.all([
|
||||
pdfManager.ensure(page, 'rotate'),
|
||||
pdfManager.ensure(page, 'ref'),
|
||||
pdfManager.ensure(page, 'userUnit'),
|
||||
pdfManager.ensure(page, 'view'),
|
||||
pdfManager.ensure(page, "rotate"),
|
||||
pdfManager.ensure(page, "ref"),
|
||||
pdfManager.ensure(page, "userUnit"),
|
||||
pdfManager.ensure(page, "view"),
|
||||
]).then(function([rotate, ref, userUnit, view]) {
|
||||
return {
|
||||
rotate,
|
||||
@ -360,201 +408,207 @@ var WorkerMessageHandler = {
|
||||
});
|
||||
});
|
||||
|
||||
handler.on('GetPageIndex', function wphSetupGetPageIndex(data) {
|
||||
handler.on("GetPageIndex", function wphSetupGetPageIndex(data) {
|
||||
var ref = Ref.get(data.ref.num, data.ref.gen);
|
||||
var catalog = pdfManager.pdfDocument.catalog;
|
||||
return catalog.getPageIndex(ref);
|
||||
});
|
||||
|
||||
handler.on('GetDestinations',
|
||||
function wphSetupGetDestinations(data) {
|
||||
return pdfManager.ensureCatalog('destinations');
|
||||
}
|
||||
);
|
||||
|
||||
handler.on('GetDestination',
|
||||
function wphSetupGetDestination(data) {
|
||||
return pdfManager.ensureCatalog('getDestination', [data.id]);
|
||||
}
|
||||
);
|
||||
|
||||
handler.on('GetPageLabels',
|
||||
function wphSetupGetPageLabels(data) {
|
||||
return pdfManager.ensureCatalog('pageLabels');
|
||||
}
|
||||
);
|
||||
|
||||
handler.on('GetPageLayout', function wphSetupGetPageLayout(data) {
|
||||
return pdfManager.ensureCatalog('pageLayout');
|
||||
handler.on("GetDestinations", function wphSetupGetDestinations(data) {
|
||||
return pdfManager.ensureCatalog("destinations");
|
||||
});
|
||||
|
||||
handler.on('GetPageMode', function wphSetupGetPageMode(data) {
|
||||
return pdfManager.ensureCatalog('pageMode');
|
||||
handler.on("GetDestination", function wphSetupGetDestination(data) {
|
||||
return pdfManager.ensureCatalog("getDestination", [data.id]);
|
||||
});
|
||||
|
||||
handler.on('GetViewerPreferences', function(data) {
|
||||
return pdfManager.ensureCatalog('viewerPreferences');
|
||||
handler.on("GetPageLabels", function wphSetupGetPageLabels(data) {
|
||||
return pdfManager.ensureCatalog("pageLabels");
|
||||
});
|
||||
|
||||
handler.on('GetOpenActionDestination', function(data) {
|
||||
return pdfManager.ensureCatalog('openActionDestination');
|
||||
handler.on("GetPageLayout", function wphSetupGetPageLayout(data) {
|
||||
return pdfManager.ensureCatalog("pageLayout");
|
||||
});
|
||||
|
||||
handler.on('GetAttachments',
|
||||
function wphSetupGetAttachments(data) {
|
||||
return pdfManager.ensureCatalog('attachments');
|
||||
}
|
||||
);
|
||||
|
||||
handler.on('GetJavaScript',
|
||||
function wphSetupGetJavaScript(data) {
|
||||
return pdfManager.ensureCatalog('javaScript');
|
||||
}
|
||||
);
|
||||
|
||||
handler.on('GetOutline',
|
||||
function wphSetupGetOutline(data) {
|
||||
return pdfManager.ensureCatalog('documentOutline');
|
||||
}
|
||||
);
|
||||
|
||||
handler.on('GetPermissions', function(data) {
|
||||
return pdfManager.ensureCatalog('permissions');
|
||||
handler.on("GetPageMode", function wphSetupGetPageMode(data) {
|
||||
return pdfManager.ensureCatalog("pageMode");
|
||||
});
|
||||
|
||||
handler.on('GetMetadata',
|
||||
function wphSetupGetMetadata(data) {
|
||||
return Promise.all([pdfManager.ensureDoc('documentInfo'),
|
||||
pdfManager.ensureCatalog('metadata')]);
|
||||
}
|
||||
);
|
||||
handler.on("GetViewerPreferences", function(data) {
|
||||
return pdfManager.ensureCatalog("viewerPreferences");
|
||||
});
|
||||
|
||||
handler.on('GetData', function wphSetupGetData(data) {
|
||||
handler.on("GetOpenActionDestination", function(data) {
|
||||
return pdfManager.ensureCatalog("openActionDestination");
|
||||
});
|
||||
|
||||
handler.on("GetAttachments", function wphSetupGetAttachments(data) {
|
||||
return pdfManager.ensureCatalog("attachments");
|
||||
});
|
||||
|
||||
handler.on("GetJavaScript", function wphSetupGetJavaScript(data) {
|
||||
return pdfManager.ensureCatalog("javaScript");
|
||||
});
|
||||
|
||||
handler.on("GetOutline", function wphSetupGetOutline(data) {
|
||||
return pdfManager.ensureCatalog("documentOutline");
|
||||
});
|
||||
|
||||
handler.on("GetPermissions", function(data) {
|
||||
return pdfManager.ensureCatalog("permissions");
|
||||
});
|
||||
|
||||
handler.on("GetMetadata", function wphSetupGetMetadata(data) {
|
||||
return Promise.all([
|
||||
pdfManager.ensureDoc("documentInfo"),
|
||||
pdfManager.ensureCatalog("metadata"),
|
||||
]);
|
||||
});
|
||||
|
||||
handler.on("GetData", function wphSetupGetData(data) {
|
||||
pdfManager.requestLoadedStream();
|
||||
return pdfManager.onLoadedStream().then(function(stream) {
|
||||
return stream.bytes;
|
||||
});
|
||||
});
|
||||
|
||||
handler.on('GetStats',
|
||||
function wphSetupGetStats(data) {
|
||||
return pdfManager.pdfDocument.xref.stats;
|
||||
}
|
||||
);
|
||||
handler.on("GetStats", function wphSetupGetStats(data) {
|
||||
return pdfManager.pdfDocument.xref.stats;
|
||||
});
|
||||
|
||||
handler.on('GetAnnotations', function({ pageIndex, intent, }) {
|
||||
handler.on("GetAnnotations", function({ pageIndex, intent }) {
|
||||
return pdfManager.getPage(pageIndex).then(function(page) {
|
||||
return page.getAnnotationsData(intent);
|
||||
});
|
||||
});
|
||||
|
||||
handler.on('GetOperatorList', function wphSetupRenderPage(data, sink) {
|
||||
handler.on(
|
||||
"GetOperatorList",
|
||||
function wphSetupRenderPage(data, sink) {
|
||||
var pageIndex = data.pageIndex;
|
||||
pdfManager.getPage(pageIndex).then(function(page) {
|
||||
var task = new WorkerTask(`GetOperatorList: page ${pageIndex}`);
|
||||
startWorkerTask(task);
|
||||
|
||||
// NOTE: Keep this condition in sync with the `info` helper function.
|
||||
const start = verbosity >= VerbosityLevel.INFOS ? Date.now() : 0;
|
||||
|
||||
// Pre compile the pdf page and fetch the fonts/images.
|
||||
page
|
||||
.getOperatorList({
|
||||
handler,
|
||||
sink,
|
||||
task,
|
||||
intent: data.intent,
|
||||
renderInteractiveForms: data.renderInteractiveForms,
|
||||
})
|
||||
.then(
|
||||
function(operatorListInfo) {
|
||||
finishWorkerTask(task);
|
||||
|
||||
if (start) {
|
||||
info(
|
||||
`page=${pageIndex + 1} - getOperatorList: time=` +
|
||||
`${Date.now() - start}ms, len=${operatorListInfo.length}`
|
||||
);
|
||||
}
|
||||
sink.close();
|
||||
},
|
||||
function(reason) {
|
||||
finishWorkerTask(task);
|
||||
if (task.terminated) {
|
||||
return; // ignoring errors from the terminated thread
|
||||
}
|
||||
// For compatibility with older behavior, generating unknown
|
||||
// unsupported feature notification on errors.
|
||||
handler.send("UnsupportedFeature", {
|
||||
featureId: UNSUPPORTED_FEATURES.unknown,
|
||||
});
|
||||
|
||||
sink.error(reason);
|
||||
|
||||
// TODO: Should `reason` be re-thrown here (currently that
|
||||
// casues "Uncaught exception: ..." messages in the
|
||||
// console)?
|
||||
}
|
||||
);
|
||||
});
|
||||
},
|
||||
this
|
||||
);
|
||||
|
||||
handler.on("GetTextContent", function wphExtractText(data, sink) {
|
||||
var pageIndex = data.pageIndex;
|
||||
sink.onPull = function(desiredSize) {};
|
||||
sink.onCancel = function(reason) {};
|
||||
|
||||
pdfManager.getPage(pageIndex).then(function(page) {
|
||||
var task = new WorkerTask(`GetOperatorList: page ${pageIndex}`);
|
||||
var task = new WorkerTask("GetTextContent: page " + pageIndex);
|
||||
startWorkerTask(task);
|
||||
|
||||
// NOTE: Keep this condition in sync with the `info` helper function.
|
||||
const start = (verbosity >= VerbosityLevel.INFOS ? Date.now() : 0);
|
||||
const start = verbosity >= VerbosityLevel.INFOS ? Date.now() : 0;
|
||||
|
||||
// Pre compile the pdf page and fetch the fonts/images.
|
||||
page.getOperatorList({
|
||||
handler,
|
||||
sink,
|
||||
task,
|
||||
intent: data.intent,
|
||||
renderInteractiveForms: data.renderInteractiveForms,
|
||||
}).then(function(operatorListInfo) {
|
||||
finishWorkerTask(task);
|
||||
page
|
||||
.extractTextContent({
|
||||
handler,
|
||||
task,
|
||||
sink,
|
||||
normalizeWhitespace: data.normalizeWhitespace,
|
||||
combineTextItems: data.combineTextItems,
|
||||
})
|
||||
.then(
|
||||
function() {
|
||||
finishWorkerTask(task);
|
||||
|
||||
if (start) {
|
||||
info(`page=${pageIndex + 1} - getOperatorList: time=` +
|
||||
`${Date.now() - start}ms, len=${operatorListInfo.length}`);
|
||||
}
|
||||
sink.close();
|
||||
}, function(reason) {
|
||||
finishWorkerTask(task);
|
||||
if (task.terminated) {
|
||||
return; // ignoring errors from the terminated thread
|
||||
}
|
||||
// For compatibility with older behavior, generating unknown
|
||||
// unsupported feature notification on errors.
|
||||
handler.send('UnsupportedFeature',
|
||||
{ featureId: UNSUPPORTED_FEATURES.unknown, });
|
||||
if (start) {
|
||||
info(
|
||||
`page=${pageIndex + 1} - getTextContent: time=` +
|
||||
`${Date.now() - start}ms`
|
||||
);
|
||||
}
|
||||
sink.close();
|
||||
},
|
||||
function(reason) {
|
||||
finishWorkerTask(task);
|
||||
if (task.terminated) {
|
||||
return; // ignoring errors from the terminated thread
|
||||
}
|
||||
sink.error(reason);
|
||||
|
||||
sink.error(reason);
|
||||
|
||||
// TODO: Should `reason` be re-thrown here (currently that casues
|
||||
// "Uncaught exception: ..." messages in the console)?
|
||||
});
|
||||
});
|
||||
}, this);
|
||||
|
||||
handler.on('GetTextContent', function wphExtractText(data, sink) {
|
||||
var pageIndex = data.pageIndex;
|
||||
sink.onPull = function (desiredSize) { };
|
||||
sink.onCancel = function (reason) { };
|
||||
|
||||
pdfManager.getPage(pageIndex).then(function(page) {
|
||||
var task = new WorkerTask('GetTextContent: page ' + pageIndex);
|
||||
startWorkerTask(task);
|
||||
|
||||
// NOTE: Keep this condition in sync with the `info` helper function.
|
||||
const start = (verbosity >= VerbosityLevel.INFOS ? Date.now() : 0);
|
||||
|
||||
page.extractTextContent({
|
||||
handler,
|
||||
task,
|
||||
sink,
|
||||
normalizeWhitespace: data.normalizeWhitespace,
|
||||
combineTextItems: data.combineTextItems,
|
||||
}).then(function() {
|
||||
finishWorkerTask(task);
|
||||
|
||||
if (start) {
|
||||
info(`page=${pageIndex + 1} - getTextContent: time=` +
|
||||
`${Date.now() - start}ms`);
|
||||
}
|
||||
sink.close();
|
||||
}, function (reason) {
|
||||
finishWorkerTask(task);
|
||||
if (task.terminated) {
|
||||
return; // ignoring errors from the terminated thread
|
||||
}
|
||||
sink.error(reason);
|
||||
|
||||
// TODO: Should `reason` be re-thrown here (currently that casues
|
||||
// "Uncaught exception: ..." messages in the console)?
|
||||
});
|
||||
// TODO: Should `reason` be re-thrown here (currently that casues
|
||||
// "Uncaught exception: ..." messages in the console)?
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
handler.on('FontFallback', function(data) {
|
||||
handler.on("FontFallback", function(data) {
|
||||
return pdfManager.fontFallback(data.id, handler);
|
||||
});
|
||||
|
||||
handler.on('Cleanup', function wphCleanup(data) {
|
||||
handler.on("Cleanup", function wphCleanup(data) {
|
||||
return pdfManager.cleanup();
|
||||
});
|
||||
|
||||
handler.on('Terminate', function wphTerminate(data) {
|
||||
handler.on("Terminate", function wphTerminate(data) {
|
||||
terminated = true;
|
||||
if (pdfManager) {
|
||||
pdfManager.terminate(new AbortException('Worker was terminated.'));
|
||||
pdfManager.terminate(new AbortException("Worker was terminated."));
|
||||
pdfManager = null;
|
||||
}
|
||||
if (cancelXHRs) {
|
||||
cancelXHRs(new AbortException('Worker was terminated.'));
|
||||
cancelXHRs(new AbortException("Worker was terminated."));
|
||||
}
|
||||
clearPrimitiveCaches();
|
||||
|
||||
var waitOn = [];
|
||||
WorkerTasks.forEach(function (task) {
|
||||
WorkerTasks.forEach(function(task) {
|
||||
waitOn.push(task.finished);
|
||||
task.terminate();
|
||||
});
|
||||
|
||||
return Promise.all(waitOn).then(function () {
|
||||
return Promise.all(waitOn).then(function() {
|
||||
// Notice that even if we destroying handler, resolved response promise
|
||||
// must be sent back.
|
||||
handler.destroy();
|
||||
@ -562,31 +616,33 @@ var WorkerMessageHandler = {
|
||||
});
|
||||
});
|
||||
|
||||
handler.on('Ready', function wphReady(data) {
|
||||
handler.on("Ready", function wphReady(data) {
|
||||
setupDoc(docParams);
|
||||
docParams = null; // we don't need docParams anymore -- saving memory.
|
||||
});
|
||||
return workerHandlerName;
|
||||
},
|
||||
initializeFromPort(port) {
|
||||
var handler = new MessageHandler('worker', 'main', port);
|
||||
var handler = new MessageHandler("worker", "main", port);
|
||||
WorkerMessageHandler.setup(handler, port);
|
||||
handler.send('ready', null);
|
||||
handler.send("ready", null);
|
||||
},
|
||||
};
|
||||
|
||||
function isMessagePort(maybePort) {
|
||||
return typeof maybePort.postMessage === 'function' &&
|
||||
('onmessage' in maybePort);
|
||||
return (
|
||||
typeof maybePort.postMessage === "function" && "onmessage" in maybePort
|
||||
);
|
||||
}
|
||||
|
||||
// Worker thread (and not node.js)?
|
||||
if (typeof window === 'undefined' && !isNodeJS &&
|
||||
typeof self !== 'undefined' && isMessagePort(self)) {
|
||||
if (
|
||||
typeof window === "undefined" &&
|
||||
!isNodeJS &&
|
||||
typeof self !== "undefined" &&
|
||||
isMessagePort(self)
|
||||
) {
|
||||
WorkerMessageHandler.initializeFromPort(self);
|
||||
}
|
||||
|
||||
export {
|
||||
WorkerTask,
|
||||
WorkerMessageHandler,
|
||||
};
|
||||
export { WorkerTask, WorkerMessageHandler };
|
||||
|
@ -14,7 +14,7 @@
|
||||
*/
|
||||
/* eslint no-var: error */
|
||||
|
||||
import { assert } from '../shared/util';
|
||||
import { assert } from "../shared/util";
|
||||
|
||||
/** @implements {IPDFStream} */
|
||||
class PDFWorkerStream {
|
||||
@ -58,15 +58,16 @@ class PDFWorkerStreamReader {
|
||||
this._isRangeSupported = false;
|
||||
this._isStreamingSupported = false;
|
||||
|
||||
const readableStream = this._msgHandler.sendWithStream('GetReader');
|
||||
const readableStream = this._msgHandler.sendWithStream("GetReader");
|
||||
this._reader = readableStream.getReader();
|
||||
|
||||
this._headersReady = this._msgHandler.sendWithPromise('ReaderHeadersReady').
|
||||
then((data) => {
|
||||
this._isStreamingSupported = data.isStreamingSupported;
|
||||
this._isRangeSupported = data.isRangeSupported;
|
||||
this._contentLength = data.contentLength;
|
||||
});
|
||||
this._headersReady = this._msgHandler
|
||||
.sendWithPromise("ReaderHeadersReady")
|
||||
.then(data => {
|
||||
this._isStreamingSupported = data.isStreamingSupported;
|
||||
this._isRangeSupported = data.isRangeSupported;
|
||||
this._contentLength = data.contentLength;
|
||||
});
|
||||
}
|
||||
|
||||
get headersReady() {
|
||||
@ -86,13 +87,13 @@ class PDFWorkerStreamReader {
|
||||
}
|
||||
|
||||
async read() {
|
||||
const { value, done, } = await this._reader.read();
|
||||
const { value, done } = await this._reader.read();
|
||||
if (done) {
|
||||
return { value: undefined, done: true, };
|
||||
return { value: undefined, done: true };
|
||||
}
|
||||
// `value` is wrapped into Uint8Array, we need to
|
||||
// unwrap it to ArrayBuffer for further processing.
|
||||
return { value: value.buffer, done: false, };
|
||||
return { value: value.buffer, done: false };
|
||||
}
|
||||
|
||||
cancel(reason) {
|
||||
@ -106,8 +107,10 @@ class PDFWorkerStreamRangeReader {
|
||||
this._msgHandler = msgHandler;
|
||||
this.onProgress = null;
|
||||
|
||||
const readableStream = this._msgHandler.sendWithStream('GetRangeReader',
|
||||
{ begin, end, });
|
||||
const readableStream = this._msgHandler.sendWithStream("GetRangeReader", {
|
||||
begin,
|
||||
end,
|
||||
});
|
||||
this._reader = readableStream.getReader();
|
||||
}
|
||||
|
||||
@ -116,11 +119,11 @@ class PDFWorkerStreamRangeReader {
|
||||
}
|
||||
|
||||
async read() {
|
||||
const { value, done, } = await this._reader.read();
|
||||
const { value, done } = await this._reader.read();
|
||||
if (done) {
|
||||
return { value: undefined, done: true, };
|
||||
return { value: undefined, done: true };
|
||||
}
|
||||
return { value: value.buffer, done: false, };
|
||||
return { value: value.buffer, done: false };
|
||||
}
|
||||
|
||||
cancel(reason) {
|
||||
@ -128,6 +131,4 @@ class PDFWorkerStreamRangeReader {
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
PDFWorkerStream,
|
||||
};
|
||||
export { PDFWorkerStream };
|
||||
|
@ -15,13 +15,20 @@
|
||||
/* eslint no-var: error */
|
||||
|
||||
import {
|
||||
addLinkAttributes, DOMSVGFactory, getFilenameFromUrl, LinkTarget,
|
||||
PDFDateString
|
||||
} from './display_utils';
|
||||
addLinkAttributes,
|
||||
DOMSVGFactory,
|
||||
getFilenameFromUrl,
|
||||
LinkTarget,
|
||||
PDFDateString,
|
||||
} from "./display_utils";
|
||||
import {
|
||||
AnnotationBorderStyleType, AnnotationType, stringToPDFString, unreachable,
|
||||
Util, warn
|
||||
} from '../shared/util';
|
||||
AnnotationBorderStyleType,
|
||||
AnnotationType,
|
||||
stringToPDFString,
|
||||
unreachable,
|
||||
Util,
|
||||
warn,
|
||||
} from "../shared/util";
|
||||
|
||||
/**
|
||||
* @typedef {Object} AnnotationElementParameters
|
||||
@ -56,16 +63,16 @@ class AnnotationElementFactory {
|
||||
const fieldType = parameters.data.fieldType;
|
||||
|
||||
switch (fieldType) {
|
||||
case 'Tx':
|
||||
case "Tx":
|
||||
return new TextWidgetAnnotationElement(parameters);
|
||||
case 'Btn':
|
||||
case "Btn":
|
||||
if (parameters.data.radioButton) {
|
||||
return new RadioButtonWidgetAnnotationElement(parameters);
|
||||
} else if (parameters.data.checkBox) {
|
||||
return new CheckboxWidgetAnnotationElement(parameters);
|
||||
}
|
||||
return new PushButtonWidgetAnnotationElement(parameters);
|
||||
case 'Ch':
|
||||
case "Ch":
|
||||
return new ChoiceWidgetAnnotationElement(parameters);
|
||||
}
|
||||
return new WidgetAnnotationElement(parameters);
|
||||
@ -148,12 +155,14 @@ class AnnotationElement {
|
||||
* @returns {HTMLSectionElement}
|
||||
*/
|
||||
_createContainer(ignoreBorder = false) {
|
||||
const data = this.data, page = this.page, viewport = this.viewport;
|
||||
const container = document.createElement('section');
|
||||
const data = this.data,
|
||||
page = this.page,
|
||||
viewport = this.viewport;
|
||||
const container = document.createElement("section");
|
||||
let width = data.rect[2] - data.rect[0];
|
||||
let height = data.rect[3] - data.rect[1];
|
||||
|
||||
container.setAttribute('data-annotation-id', data.id);
|
||||
container.setAttribute("data-annotation-id", data.id);
|
||||
|
||||
// Do *not* modify `data.rect`, since that will corrupt the annotation
|
||||
// position on subsequent calls to `_createContainer` (see issue 6804).
|
||||
@ -161,10 +170,10 @@ class AnnotationElement {
|
||||
data.rect[0],
|
||||
page.view[3] - data.rect[1] + page.view[1],
|
||||
data.rect[2],
|
||||
page.view[3] - data.rect[3] + page.view[1]
|
||||
page.view[3] - data.rect[3] + page.view[1],
|
||||
]);
|
||||
|
||||
container.style.transform = `matrix(${viewport.transform.join(',')})`;
|
||||
container.style.transform = `matrix(${viewport.transform.join(",")})`;
|
||||
container.style.transformOrigin = `-${rect[0]}px -${rect[1]}px`;
|
||||
|
||||
if (!ignoreBorder && data.borderStyle.width > 0) {
|
||||
@ -186,23 +195,23 @@ class AnnotationElement {
|
||||
|
||||
switch (data.borderStyle.style) {
|
||||
case AnnotationBorderStyleType.SOLID:
|
||||
container.style.borderStyle = 'solid';
|
||||
container.style.borderStyle = "solid";
|
||||
break;
|
||||
|
||||
case AnnotationBorderStyleType.DASHED:
|
||||
container.style.borderStyle = 'dashed';
|
||||
container.style.borderStyle = "dashed";
|
||||
break;
|
||||
|
||||
case AnnotationBorderStyleType.BEVELED:
|
||||
warn('Unimplemented border style: beveled');
|
||||
warn("Unimplemented border style: beveled");
|
||||
break;
|
||||
|
||||
case AnnotationBorderStyleType.INSET:
|
||||
warn('Unimplemented border style: inset');
|
||||
warn("Unimplemented border style: inset");
|
||||
break;
|
||||
|
||||
case AnnotationBorderStyleType.UNDERLINE:
|
||||
container.style.borderBottomStyle = 'solid';
|
||||
container.style.borderBottomStyle = "solid";
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -210,9 +219,11 @@ class AnnotationElement {
|
||||
}
|
||||
|
||||
if (data.color) {
|
||||
container.style.borderColor = Util.makeCssRgb(data.color[0] | 0,
|
||||
data.color[1] | 0,
|
||||
data.color[2] | 0);
|
||||
container.style.borderColor = Util.makeCssRgb(
|
||||
data.color[0] | 0,
|
||||
data.color[1] | 0,
|
||||
data.color[2] | 0
|
||||
);
|
||||
} else {
|
||||
// Transparent (invisible) border, so do not draw it at all.
|
||||
container.style.borderWidth = 0;
|
||||
@ -240,7 +251,7 @@ class AnnotationElement {
|
||||
_createPopup(container, trigger, data) {
|
||||
// If no trigger element is specified, create it.
|
||||
if (!trigger) {
|
||||
trigger = document.createElement('div');
|
||||
trigger = document.createElement("div");
|
||||
trigger.style.height = container.style.height;
|
||||
trigger.style.width = container.style.width;
|
||||
container.appendChild(trigger);
|
||||
@ -270,14 +281,17 @@ class AnnotationElement {
|
||||
* @memberof AnnotationElement
|
||||
*/
|
||||
render() {
|
||||
unreachable('Abstract method `AnnotationElement.render` called');
|
||||
unreachable("Abstract method `AnnotationElement.render` called");
|
||||
}
|
||||
}
|
||||
|
||||
class LinkAnnotationElement extends AnnotationElement {
|
||||
constructor(parameters) {
|
||||
const isRenderable = !!(parameters.data.url || parameters.data.dest ||
|
||||
parameters.data.action);
|
||||
const isRenderable = !!(
|
||||
parameters.data.url ||
|
||||
parameters.data.dest ||
|
||||
parameters.data.action
|
||||
);
|
||||
super(parameters, isRenderable);
|
||||
}
|
||||
|
||||
@ -289,16 +303,17 @@ class LinkAnnotationElement extends AnnotationElement {
|
||||
* @returns {HTMLSectionElement}
|
||||
*/
|
||||
render() {
|
||||
this.container.className = 'linkAnnotation';
|
||||
this.container.className = "linkAnnotation";
|
||||
|
||||
const { data, linkService, } = this;
|
||||
const link = document.createElement('a');
|
||||
const { data, linkService } = this;
|
||||
const link = document.createElement("a");
|
||||
|
||||
if (data.url) {
|
||||
addLinkAttributes(link, {
|
||||
url: data.url,
|
||||
target: (data.newWindow ?
|
||||
LinkTarget.BLANK : linkService.externalLinkTarget),
|
||||
target: data.newWindow
|
||||
? LinkTarget.BLANK
|
||||
: linkService.externalLinkTarget,
|
||||
rel: linkService.externalLinkRel,
|
||||
enabled: linkService.externalLinkEnabled,
|
||||
});
|
||||
@ -329,7 +344,7 @@ class LinkAnnotationElement extends AnnotationElement {
|
||||
return false;
|
||||
};
|
||||
if (destination) {
|
||||
link.className = 'internalLink';
|
||||
link.className = "internalLink";
|
||||
}
|
||||
}
|
||||
|
||||
@ -342,19 +357,22 @@ class LinkAnnotationElement extends AnnotationElement {
|
||||
* @memberof LinkAnnotationElement
|
||||
*/
|
||||
_bindNamedAction(link, action) {
|
||||
link.href = this.linkService.getAnchorUrl('');
|
||||
link.href = this.linkService.getAnchorUrl("");
|
||||
link.onclick = () => {
|
||||
this.linkService.executeNamedAction(action);
|
||||
return false;
|
||||
};
|
||||
link.className = 'internalLink';
|
||||
link.className = "internalLink";
|
||||
}
|
||||
}
|
||||
|
||||
class TextAnnotationElement extends AnnotationElement {
|
||||
constructor(parameters) {
|
||||
const isRenderable = !!(parameters.data.hasPopup ||
|
||||
parameters.data.title || parameters.data.contents);
|
||||
const isRenderable = !!(
|
||||
parameters.data.hasPopup ||
|
||||
parameters.data.title ||
|
||||
parameters.data.contents
|
||||
);
|
||||
super(parameters, isRenderable);
|
||||
}
|
||||
|
||||
@ -366,16 +384,19 @@ class TextAnnotationElement extends AnnotationElement {
|
||||
* @returns {HTMLSectionElement}
|
||||
*/
|
||||
render() {
|
||||
this.container.className = 'textAnnotation';
|
||||
this.container.className = "textAnnotation";
|
||||
|
||||
const image = document.createElement('img');
|
||||
const image = document.createElement("img");
|
||||
image.style.height = this.container.style.height;
|
||||
image.style.width = this.container.style.width;
|
||||
image.src = this.imageResourcesPath + 'annotation-' +
|
||||
this.data.name.toLowerCase() + '.svg';
|
||||
image.alt = '[{{type}} Annotation]';
|
||||
image.dataset.l10nId = 'text_annotation_type';
|
||||
image.dataset.l10nArgs = JSON.stringify({ type: this.data.name, });
|
||||
image.src =
|
||||
this.imageResourcesPath +
|
||||
"annotation-" +
|
||||
this.data.name.toLowerCase() +
|
||||
".svg";
|
||||
image.alt = "[{{type}} Annotation]";
|
||||
image.dataset.l10nId = "text_annotation_type";
|
||||
image.dataset.l10nArgs = JSON.stringify({ type: this.data.name });
|
||||
|
||||
if (!this.data.hasPopup) {
|
||||
this._createPopup(this.container, image, this.data);
|
||||
@ -402,7 +423,8 @@ class WidgetAnnotationElement extends AnnotationElement {
|
||||
|
||||
class TextWidgetAnnotationElement extends WidgetAnnotationElement {
|
||||
constructor(parameters) {
|
||||
const isRenderable = parameters.renderInteractiveForms ||
|
||||
const isRenderable =
|
||||
parameters.renderInteractiveForms ||
|
||||
(!parameters.data.hasAppearance && !!parameters.data.fieldValue);
|
||||
super(parameters, isRenderable);
|
||||
}
|
||||
@ -415,9 +437,9 @@ class TextWidgetAnnotationElement extends WidgetAnnotationElement {
|
||||
* @returns {HTMLSectionElement}
|
||||
*/
|
||||
render() {
|
||||
const TEXT_ALIGNMENT = ['left', 'center', 'right'];
|
||||
const TEXT_ALIGNMENT = ["left", "center", "right"];
|
||||
|
||||
this.container.className = 'textWidgetAnnotation';
|
||||
this.container.className = "textWidgetAnnotation";
|
||||
|
||||
let element = null;
|
||||
if (this.renderInteractiveForms) {
|
||||
@ -425,12 +447,12 @@ class TextWidgetAnnotationElement extends WidgetAnnotationElement {
|
||||
// prevents the AnnotationLayer rasterizer in `test/driver.js`
|
||||
// from parsing the elements correctly for the reference tests.
|
||||
if (this.data.multiLine) {
|
||||
element = document.createElement('textarea');
|
||||
element = document.createElement("textarea");
|
||||
element.textContent = this.data.fieldValue;
|
||||
} else {
|
||||
element = document.createElement('input');
|
||||
element.type = 'text';
|
||||
element.setAttribute('value', this.data.fieldValue);
|
||||
element = document.createElement("input");
|
||||
element.type = "text";
|
||||
element.setAttribute("value", this.data.fieldValue);
|
||||
}
|
||||
|
||||
element.disabled = this.data.readOnly;
|
||||
@ -443,18 +465,20 @@ class TextWidgetAnnotationElement extends WidgetAnnotationElement {
|
||||
const fieldWidth = this.data.rect[2] - this.data.rect[0];
|
||||
const combWidth = fieldWidth / this.data.maxLen;
|
||||
|
||||
element.classList.add('comb');
|
||||
element.classList.add("comb");
|
||||
element.style.letterSpacing = `calc(${combWidth}px - 1ch)`;
|
||||
}
|
||||
} else {
|
||||
element = document.createElement('div');
|
||||
element = document.createElement("div");
|
||||
element.textContent = this.data.fieldValue;
|
||||
element.style.verticalAlign = 'middle';
|
||||
element.style.display = 'table-cell';
|
||||
element.style.verticalAlign = "middle";
|
||||
element.style.display = "table-cell";
|
||||
|
||||
let font = null;
|
||||
if (this.data.fontRefName &&
|
||||
this.page.commonObjs.has(this.data.fontRefName)) {
|
||||
if (
|
||||
this.data.fontRefName &&
|
||||
this.page.commonObjs.has(this.data.fontRefName)
|
||||
) {
|
||||
font = this.page.commonObjs.get(this.data.fontRefName);
|
||||
}
|
||||
this._setTextStyle(element, font);
|
||||
@ -480,20 +504,24 @@ class TextWidgetAnnotationElement extends WidgetAnnotationElement {
|
||||
// TODO: This duplicates some of the logic in CanvasGraphics.setFont().
|
||||
const style = element.style;
|
||||
style.fontSize = `${this.data.fontSize}px`;
|
||||
style.direction = (this.data.fontDirection < 0 ? 'rtl' : 'ltr');
|
||||
style.direction = this.data.fontDirection < 0 ? "rtl" : "ltr";
|
||||
|
||||
if (!font) {
|
||||
return;
|
||||
}
|
||||
|
||||
style.fontWeight = (font.black ?
|
||||
(font.bold ? '900' : 'bold') :
|
||||
(font.bold ? 'bold' : 'normal'));
|
||||
style.fontStyle = (font.italic ? 'italic' : 'normal');
|
||||
style.fontWeight = font.black
|
||||
? font.bold
|
||||
? "900"
|
||||
: "bold"
|
||||
: font.bold
|
||||
? "bold"
|
||||
: "normal";
|
||||
style.fontStyle = font.italic ? "italic" : "normal";
|
||||
|
||||
// Use a reasonable default font if the font doesn't specify a fallback.
|
||||
const fontFamily = font.loadedName ? `"${font.loadedName}", ` : '';
|
||||
const fallbackName = font.fallbackName || 'Helvetica, sans-serif';
|
||||
const fontFamily = font.loadedName ? `"${font.loadedName}", ` : "";
|
||||
const fallbackName = font.fallbackName || "Helvetica, sans-serif";
|
||||
style.fontFamily = fontFamily + fallbackName;
|
||||
}
|
||||
}
|
||||
@ -512,13 +540,13 @@ class CheckboxWidgetAnnotationElement extends WidgetAnnotationElement {
|
||||
* @returns {HTMLSectionElement}
|
||||
*/
|
||||
render() {
|
||||
this.container.className = 'buttonWidgetAnnotation checkBox';
|
||||
this.container.className = "buttonWidgetAnnotation checkBox";
|
||||
|
||||
const element = document.createElement('input');
|
||||
const element = document.createElement("input");
|
||||
element.disabled = this.data.readOnly;
|
||||
element.type = 'checkbox';
|
||||
if (this.data.fieldValue && this.data.fieldValue !== 'Off') {
|
||||
element.setAttribute('checked', true);
|
||||
element.type = "checkbox";
|
||||
if (this.data.fieldValue && this.data.fieldValue !== "Off") {
|
||||
element.setAttribute("checked", true);
|
||||
}
|
||||
|
||||
this.container.appendChild(element);
|
||||
@ -540,14 +568,14 @@ class RadioButtonWidgetAnnotationElement extends WidgetAnnotationElement {
|
||||
* @returns {HTMLSectionElement}
|
||||
*/
|
||||
render() {
|
||||
this.container.className = 'buttonWidgetAnnotation radioButton';
|
||||
this.container.className = "buttonWidgetAnnotation radioButton";
|
||||
|
||||
const element = document.createElement('input');
|
||||
const element = document.createElement("input");
|
||||
element.disabled = this.data.readOnly;
|
||||
element.type = 'radio';
|
||||
element.type = "radio";
|
||||
element.name = this.data.fieldName;
|
||||
if (this.data.fieldValue === this.data.buttonValue) {
|
||||
element.setAttribute('checked', true);
|
||||
element.setAttribute("checked", true);
|
||||
}
|
||||
|
||||
this.container.appendChild(element);
|
||||
@ -569,7 +597,7 @@ class PushButtonWidgetAnnotationElement extends LinkAnnotationElement {
|
||||
// equal to that of a link annotation, but may have more functionality, such
|
||||
// as performing actions on form fields (resetting, submitting, et cetera).
|
||||
const container = super.render();
|
||||
container.className = 'buttonWidgetAnnotation pushButton';
|
||||
container.className = "buttonWidgetAnnotation pushButton";
|
||||
return container;
|
||||
}
|
||||
}
|
||||
@ -588,9 +616,9 @@ class ChoiceWidgetAnnotationElement extends WidgetAnnotationElement {
|
||||
* @returns {HTMLSectionElement}
|
||||
*/
|
||||
render() {
|
||||
this.container.className = 'choiceWidgetAnnotation';
|
||||
this.container.className = "choiceWidgetAnnotation";
|
||||
|
||||
const selectElement = document.createElement('select');
|
||||
const selectElement = document.createElement("select");
|
||||
selectElement.disabled = this.data.readOnly;
|
||||
|
||||
if (!this.data.combo) {
|
||||
@ -603,11 +631,11 @@ class ChoiceWidgetAnnotationElement extends WidgetAnnotationElement {
|
||||
|
||||
// Insert the options into the choice field.
|
||||
for (const option of this.data.options) {
|
||||
const optionElement = document.createElement('option');
|
||||
const optionElement = document.createElement("option");
|
||||
optionElement.textContent = option.displayValue;
|
||||
optionElement.value = option.exportValue;
|
||||
if (this.data.fieldValue.includes(option.displayValue)) {
|
||||
optionElement.setAttribute('selected', true);
|
||||
optionElement.setAttribute("selected", true);
|
||||
}
|
||||
selectElement.appendChild(optionElement);
|
||||
}
|
||||
@ -634,15 +662,15 @@ class PopupAnnotationElement extends AnnotationElement {
|
||||
// Do not render popup annotations for parent elements with these types as
|
||||
// they create the popups themselves (because of custom trigger divs).
|
||||
const IGNORE_TYPES = [
|
||||
'Line',
|
||||
'Square',
|
||||
'Circle',
|
||||
'PolyLine',
|
||||
'Polygon',
|
||||
'Ink',
|
||||
"Line",
|
||||
"Square",
|
||||
"Circle",
|
||||
"PolyLine",
|
||||
"Polygon",
|
||||
"Ink",
|
||||
];
|
||||
|
||||
this.container.className = 'popupAnnotation';
|
||||
this.container.className = "popupAnnotation";
|
||||
|
||||
if (IGNORE_TYPES.includes(this.data.parentType)) {
|
||||
return this.container;
|
||||
@ -667,8 +695,9 @@ class PopupAnnotationElement extends AnnotationElement {
|
||||
// PDF viewers ignore a popup annotation's rectangle.
|
||||
const parentLeft = parseFloat(parentElement.style.left);
|
||||
const parentWidth = parseFloat(parentElement.style.width);
|
||||
this.container.style.transformOrigin =
|
||||
`-${parentLeft + parentWidth}px -${parentElement.style.top}`;
|
||||
this.container.style.transformOrigin = `-${parentLeft + parentWidth}px -${
|
||||
parentElement.style.top
|
||||
}`;
|
||||
this.container.style.left = `${parentLeft + parentWidth}px`;
|
||||
|
||||
this.container.appendChild(popup.render());
|
||||
@ -699,18 +728,18 @@ class PopupElement {
|
||||
render() {
|
||||
const BACKGROUND_ENLIGHT = 0.7;
|
||||
|
||||
const wrapper = document.createElement('div');
|
||||
wrapper.className = 'popupWrapper';
|
||||
const wrapper = document.createElement("div");
|
||||
wrapper.className = "popupWrapper";
|
||||
|
||||
// For Popup annotations we hide the entire section because it contains
|
||||
// only the popup. However, for Text annotations without a separate Popup
|
||||
// annotation, we cannot hide the entire container as the image would
|
||||
// disappear too. In that special case, hiding the wrapper suffices.
|
||||
this.hideElement = (this.hideWrapper ? wrapper : this.container);
|
||||
this.hideElement.setAttribute('hidden', true);
|
||||
this.hideElement = this.hideWrapper ? wrapper : this.container;
|
||||
this.hideElement.setAttribute("hidden", true);
|
||||
|
||||
const popup = document.createElement('div');
|
||||
popup.className = 'popup';
|
||||
const popup = document.createElement("div");
|
||||
popup.className = "popup";
|
||||
|
||||
const color = this.color;
|
||||
if (color) {
|
||||
@ -721,7 +750,7 @@ class PopupElement {
|
||||
popup.style.backgroundColor = Util.makeCssRgb(r | 0, g | 0, b | 0);
|
||||
}
|
||||
|
||||
const title = document.createElement('h1');
|
||||
const title = document.createElement("h1");
|
||||
title.textContent = this.title;
|
||||
popup.appendChild(title);
|
||||
|
||||
@ -730,9 +759,9 @@ class PopupElement {
|
||||
// consistent with other viewers such as Adobe Acrobat.
|
||||
const dateObject = PDFDateString.toDateObject(this.modificationDate);
|
||||
if (dateObject) {
|
||||
const modificationDate = document.createElement('span');
|
||||
modificationDate.textContent = '{{date}}, {{time}}';
|
||||
modificationDate.dataset.l10nId = 'annotation_date_string';
|
||||
const modificationDate = document.createElement("span");
|
||||
modificationDate.textContent = "{{date}}, {{time}}";
|
||||
modificationDate.dataset.l10nId = "annotation_date_string";
|
||||
modificationDate.dataset.l10nArgs = JSON.stringify({
|
||||
date: dateObject.toLocaleDateString(),
|
||||
time: dateObject.toLocaleTimeString(),
|
||||
@ -744,10 +773,10 @@ class PopupElement {
|
||||
popup.appendChild(contents);
|
||||
|
||||
// Attach the event listeners to the trigger element.
|
||||
this.trigger.addEventListener('click', this._toggle.bind(this));
|
||||
this.trigger.addEventListener('mouseover', this._show.bind(this, false));
|
||||
this.trigger.addEventListener('mouseout', this._hide.bind(this, false));
|
||||
popup.addEventListener('click', this._hide.bind(this, true));
|
||||
this.trigger.addEventListener("click", this._toggle.bind(this));
|
||||
this.trigger.addEventListener("mouseover", this._show.bind(this, false));
|
||||
this.trigger.addEventListener("mouseout", this._hide.bind(this, false));
|
||||
popup.addEventListener("click", this._hide.bind(this, true));
|
||||
|
||||
wrapper.appendChild(popup);
|
||||
return wrapper;
|
||||
@ -762,13 +791,13 @@ class PopupElement {
|
||||
* @returns {HTMLParagraphElement}
|
||||
*/
|
||||
_formatContents(contents) {
|
||||
const p = document.createElement('p');
|
||||
const p = document.createElement("p");
|
||||
const lines = contents.split(/(?:\r\n?|\n)/);
|
||||
for (let i = 0, ii = lines.length; i < ii; ++i) {
|
||||
const line = lines[i];
|
||||
p.appendChild(document.createTextNode(line));
|
||||
if (i < (ii - 1)) {
|
||||
p.appendChild(document.createElement('br'));
|
||||
if (i < ii - 1) {
|
||||
p.appendChild(document.createElement("br"));
|
||||
}
|
||||
}
|
||||
return p;
|
||||
@ -799,8 +828,8 @@ class PopupElement {
|
||||
if (pin) {
|
||||
this.pinned = true;
|
||||
}
|
||||
if (this.hideElement.hasAttribute('hidden')) {
|
||||
this.hideElement.removeAttribute('hidden');
|
||||
if (this.hideElement.hasAttribute("hidden")) {
|
||||
this.hideElement.removeAttribute("hidden");
|
||||
this.container.style.zIndex += 1;
|
||||
}
|
||||
}
|
||||
@ -816,8 +845,8 @@ class PopupElement {
|
||||
if (unpin) {
|
||||
this.pinned = false;
|
||||
}
|
||||
if (!this.hideElement.hasAttribute('hidden') && !this.pinned) {
|
||||
this.hideElement.setAttribute('hidden', true);
|
||||
if (!this.hideElement.hasAttribute("hidden") && !this.pinned) {
|
||||
this.hideElement.setAttribute("hidden", true);
|
||||
this.container.style.zIndex -= 1;
|
||||
}
|
||||
}
|
||||
@ -825,8 +854,11 @@ class PopupElement {
|
||||
|
||||
class FreeTextAnnotationElement extends AnnotationElement {
|
||||
constructor(parameters) {
|
||||
const isRenderable = !!(parameters.data.hasPopup ||
|
||||
parameters.data.title || parameters.data.contents);
|
||||
const isRenderable = !!(
|
||||
parameters.data.hasPopup ||
|
||||
parameters.data.title ||
|
||||
parameters.data.contents
|
||||
);
|
||||
super(parameters, isRenderable, /* ignoreBorder = */ true);
|
||||
}
|
||||
|
||||
@ -838,7 +870,7 @@ class FreeTextAnnotationElement extends AnnotationElement {
|
||||
* @returns {HTMLSectionElement}
|
||||
*/
|
||||
render() {
|
||||
this.container.className = 'freeTextAnnotation';
|
||||
this.container.className = "freeTextAnnotation";
|
||||
|
||||
if (!this.data.hasPopup) {
|
||||
this._createPopup(this.container, null, this.data);
|
||||
@ -849,8 +881,11 @@ class FreeTextAnnotationElement extends AnnotationElement {
|
||||
|
||||
class LineAnnotationElement extends AnnotationElement {
|
||||
constructor(parameters) {
|
||||
const isRenderable = !!(parameters.data.hasPopup ||
|
||||
parameters.data.title || parameters.data.contents);
|
||||
const isRenderable = !!(
|
||||
parameters.data.hasPopup ||
|
||||
parameters.data.title ||
|
||||
parameters.data.contents
|
||||
);
|
||||
super(parameters, isRenderable, /* ignoreBorder = */ true);
|
||||
}
|
||||
|
||||
@ -862,7 +897,7 @@ class LineAnnotationElement extends AnnotationElement {
|
||||
* @returns {HTMLSectionElement}
|
||||
*/
|
||||
render() {
|
||||
this.container.className = 'lineAnnotation';
|
||||
this.container.className = "lineAnnotation";
|
||||
|
||||
// Create an invisible line with the same starting and ending coordinates
|
||||
// that acts as the trigger for the popup. Only the line itself should
|
||||
@ -874,15 +909,15 @@ class LineAnnotationElement extends AnnotationElement {
|
||||
|
||||
// PDF coordinates are calculated from a bottom left origin, so transform
|
||||
// the line coordinates to a top left origin for the SVG element.
|
||||
const line = this.svgFactory.createElement('svg:line');
|
||||
line.setAttribute('x1', data.rect[2] - data.lineCoordinates[0]);
|
||||
line.setAttribute('y1', data.rect[3] - data.lineCoordinates[1]);
|
||||
line.setAttribute('x2', data.rect[2] - data.lineCoordinates[2]);
|
||||
line.setAttribute('y2', data.rect[3] - data.lineCoordinates[3]);
|
||||
const line = this.svgFactory.createElement("svg:line");
|
||||
line.setAttribute("x1", data.rect[2] - data.lineCoordinates[0]);
|
||||
line.setAttribute("y1", data.rect[3] - data.lineCoordinates[1]);
|
||||
line.setAttribute("x2", data.rect[2] - data.lineCoordinates[2]);
|
||||
line.setAttribute("y2", data.rect[3] - data.lineCoordinates[3]);
|
||||
// Ensure that the 'stroke-width' is always non-zero, since otherwise it
|
||||
// won't be possible to open/close the popup (note e.g. issue 11122).
|
||||
line.setAttribute('stroke-width', data.borderStyle.width || 1);
|
||||
line.setAttribute('stroke', 'transparent');
|
||||
line.setAttribute("stroke-width", data.borderStyle.width || 1);
|
||||
line.setAttribute("stroke", "transparent");
|
||||
|
||||
svg.appendChild(line);
|
||||
this.container.append(svg);
|
||||
@ -897,8 +932,11 @@ class LineAnnotationElement extends AnnotationElement {
|
||||
|
||||
class SquareAnnotationElement extends AnnotationElement {
|
||||
constructor(parameters) {
|
||||
const isRenderable = !!(parameters.data.hasPopup ||
|
||||
parameters.data.title || parameters.data.contents);
|
||||
const isRenderable = !!(
|
||||
parameters.data.hasPopup ||
|
||||
parameters.data.title ||
|
||||
parameters.data.contents
|
||||
);
|
||||
super(parameters, isRenderable, /* ignoreBorder = */ true);
|
||||
}
|
||||
|
||||
@ -910,7 +948,7 @@ class SquareAnnotationElement extends AnnotationElement {
|
||||
* @returns {HTMLSectionElement}
|
||||
*/
|
||||
render() {
|
||||
this.container.className = 'squareAnnotation';
|
||||
this.container.className = "squareAnnotation";
|
||||
|
||||
// Create an invisible square with the same rectangle that acts as the
|
||||
// trigger for the popup. Only the square itself should trigger the
|
||||
@ -924,16 +962,16 @@ class SquareAnnotationElement extends AnnotationElement {
|
||||
// the borders outside the square by default. This behavior cannot be
|
||||
// changed programmatically, so correct for that here.
|
||||
const borderWidth = data.borderStyle.width;
|
||||
const square = this.svgFactory.createElement('svg:rect');
|
||||
square.setAttribute('x', borderWidth / 2);
|
||||
square.setAttribute('y', borderWidth / 2);
|
||||
square.setAttribute('width', width - borderWidth);
|
||||
square.setAttribute('height', height - borderWidth);
|
||||
const square = this.svgFactory.createElement("svg:rect");
|
||||
square.setAttribute("x", borderWidth / 2);
|
||||
square.setAttribute("y", borderWidth / 2);
|
||||
square.setAttribute("width", width - borderWidth);
|
||||
square.setAttribute("height", height - borderWidth);
|
||||
// Ensure that the 'stroke-width' is always non-zero, since otherwise it
|
||||
// won't be possible to open/close the popup (note e.g. issue 11122).
|
||||
square.setAttribute('stroke-width', borderWidth || 1);
|
||||
square.setAttribute('stroke', 'transparent');
|
||||
square.setAttribute('fill', 'none');
|
||||
square.setAttribute("stroke-width", borderWidth || 1);
|
||||
square.setAttribute("stroke", "transparent");
|
||||
square.setAttribute("fill", "none");
|
||||
|
||||
svg.appendChild(square);
|
||||
this.container.append(svg);
|
||||
@ -948,8 +986,11 @@ class SquareAnnotationElement extends AnnotationElement {
|
||||
|
||||
class CircleAnnotationElement extends AnnotationElement {
|
||||
constructor(parameters) {
|
||||
const isRenderable = !!(parameters.data.hasPopup ||
|
||||
parameters.data.title || parameters.data.contents);
|
||||
const isRenderable = !!(
|
||||
parameters.data.hasPopup ||
|
||||
parameters.data.title ||
|
||||
parameters.data.contents
|
||||
);
|
||||
super(parameters, isRenderable, /* ignoreBorder = */ true);
|
||||
}
|
||||
|
||||
@ -961,7 +1002,7 @@ class CircleAnnotationElement extends AnnotationElement {
|
||||
* @returns {HTMLSectionElement}
|
||||
*/
|
||||
render() {
|
||||
this.container.className = 'circleAnnotation';
|
||||
this.container.className = "circleAnnotation";
|
||||
|
||||
// Create an invisible circle with the same ellipse that acts as the
|
||||
// trigger for the popup. Only the circle itself should trigger the
|
||||
@ -975,16 +1016,16 @@ class CircleAnnotationElement extends AnnotationElement {
|
||||
// the borders outside the circle by default. This behavior cannot be
|
||||
// changed programmatically, so correct for that here.
|
||||
const borderWidth = data.borderStyle.width;
|
||||
const circle = this.svgFactory.createElement('svg:ellipse');
|
||||
circle.setAttribute('cx', width / 2);
|
||||
circle.setAttribute('cy', height / 2);
|
||||
circle.setAttribute('rx', (width / 2) - (borderWidth / 2));
|
||||
circle.setAttribute('ry', (height / 2) - (borderWidth / 2));
|
||||
const circle = this.svgFactory.createElement("svg:ellipse");
|
||||
circle.setAttribute("cx", width / 2);
|
||||
circle.setAttribute("cy", height / 2);
|
||||
circle.setAttribute("rx", width / 2 - borderWidth / 2);
|
||||
circle.setAttribute("ry", height / 2 - borderWidth / 2);
|
||||
// Ensure that the 'stroke-width' is always non-zero, since otherwise it
|
||||
// won't be possible to open/close the popup (note e.g. issue 11122).
|
||||
circle.setAttribute('stroke-width', borderWidth || 1);
|
||||
circle.setAttribute('stroke', 'transparent');
|
||||
circle.setAttribute('fill', 'none');
|
||||
circle.setAttribute("stroke-width", borderWidth || 1);
|
||||
circle.setAttribute("stroke", "transparent");
|
||||
circle.setAttribute("fill", "none");
|
||||
|
||||
svg.appendChild(circle);
|
||||
this.container.append(svg);
|
||||
@ -999,12 +1040,15 @@ class CircleAnnotationElement extends AnnotationElement {
|
||||
|
||||
class PolylineAnnotationElement extends AnnotationElement {
|
||||
constructor(parameters) {
|
||||
const isRenderable = !!(parameters.data.hasPopup ||
|
||||
parameters.data.title || parameters.data.contents);
|
||||
const isRenderable = !!(
|
||||
parameters.data.hasPopup ||
|
||||
parameters.data.title ||
|
||||
parameters.data.contents
|
||||
);
|
||||
super(parameters, isRenderable, /* ignoreBorder = */ true);
|
||||
|
||||
this.containerClassName = 'polylineAnnotation';
|
||||
this.svgElementName = 'svg:polyline';
|
||||
this.containerClassName = "polylineAnnotation";
|
||||
this.svgElementName = "svg:polyline";
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1033,17 +1077,17 @@ class PolylineAnnotationElement extends AnnotationElement {
|
||||
for (const coordinate of data.vertices) {
|
||||
const x = coordinate.x - data.rect[0];
|
||||
const y = data.rect[3] - coordinate.y;
|
||||
points.push(x + ',' + y);
|
||||
points.push(x + "," + y);
|
||||
}
|
||||
points = points.join(' ');
|
||||
points = points.join(" ");
|
||||
|
||||
const polyline = this.svgFactory.createElement(this.svgElementName);
|
||||
polyline.setAttribute('points', points);
|
||||
polyline.setAttribute("points", points);
|
||||
// Ensure that the 'stroke-width' is always non-zero, since otherwise it
|
||||
// won't be possible to open/close the popup (note e.g. issue 11122).
|
||||
polyline.setAttribute('stroke-width', data.borderStyle.width || 1);
|
||||
polyline.setAttribute('stroke', 'transparent');
|
||||
polyline.setAttribute('fill', 'none');
|
||||
polyline.setAttribute("stroke-width", data.borderStyle.width || 1);
|
||||
polyline.setAttribute("stroke", "transparent");
|
||||
polyline.setAttribute("fill", "none");
|
||||
|
||||
svg.appendChild(polyline);
|
||||
this.container.append(svg);
|
||||
@ -1061,15 +1105,18 @@ class PolygonAnnotationElement extends PolylineAnnotationElement {
|
||||
// Polygons are specific forms of polylines, so reuse their logic.
|
||||
super(parameters);
|
||||
|
||||
this.containerClassName = 'polygonAnnotation';
|
||||
this.svgElementName = 'svg:polygon';
|
||||
this.containerClassName = "polygonAnnotation";
|
||||
this.svgElementName = "svg:polygon";
|
||||
}
|
||||
}
|
||||
|
||||
class CaretAnnotationElement extends AnnotationElement {
|
||||
constructor(parameters) {
|
||||
const isRenderable = !!(parameters.data.hasPopup ||
|
||||
parameters.data.title || parameters.data.contents);
|
||||
const isRenderable = !!(
|
||||
parameters.data.hasPopup ||
|
||||
parameters.data.title ||
|
||||
parameters.data.contents
|
||||
);
|
||||
super(parameters, isRenderable, /* ignoreBorder = */ true);
|
||||
}
|
||||
|
||||
@ -1081,7 +1128,7 @@ class CaretAnnotationElement extends AnnotationElement {
|
||||
* @returns {HTMLSectionElement}
|
||||
*/
|
||||
render() {
|
||||
this.container.className = 'caretAnnotation';
|
||||
this.container.className = "caretAnnotation";
|
||||
|
||||
if (!this.data.hasPopup) {
|
||||
this._createPopup(this.container, null, this.data);
|
||||
@ -1092,15 +1139,18 @@ class CaretAnnotationElement extends AnnotationElement {
|
||||
|
||||
class InkAnnotationElement extends AnnotationElement {
|
||||
constructor(parameters) {
|
||||
const isRenderable = !!(parameters.data.hasPopup ||
|
||||
parameters.data.title || parameters.data.contents);
|
||||
const isRenderable = !!(
|
||||
parameters.data.hasPopup ||
|
||||
parameters.data.title ||
|
||||
parameters.data.contents
|
||||
);
|
||||
super(parameters, isRenderable, /* ignoreBorder = */ true);
|
||||
|
||||
this.containerClassName = 'inkAnnotation';
|
||||
this.containerClassName = "inkAnnotation";
|
||||
|
||||
// Use the polyline SVG element since it allows us to use coordinates
|
||||
// directly and to draw both straight lines and curves.
|
||||
this.svgElementName = 'svg:polyline';
|
||||
this.svgElementName = "svg:polyline";
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1131,15 +1181,15 @@ class InkAnnotationElement extends AnnotationElement {
|
||||
const y = data.rect[3] - coordinate.y;
|
||||
points.push(`${x},${y}`);
|
||||
}
|
||||
points = points.join(' ');
|
||||
points = points.join(" ");
|
||||
|
||||
const polyline = this.svgFactory.createElement(this.svgElementName);
|
||||
polyline.setAttribute('points', points);
|
||||
polyline.setAttribute("points", points);
|
||||
// Ensure that the 'stroke-width' is always non-zero, since otherwise it
|
||||
// won't be possible to open/close the popup (note e.g. issue 11122).
|
||||
polyline.setAttribute('stroke-width', data.borderStyle.width || 1);
|
||||
polyline.setAttribute('stroke', 'transparent');
|
||||
polyline.setAttribute('fill', 'none');
|
||||
polyline.setAttribute("stroke-width", data.borderStyle.width || 1);
|
||||
polyline.setAttribute("stroke", "transparent");
|
||||
polyline.setAttribute("fill", "none");
|
||||
|
||||
// Create the popup ourselves so that we can bind it to the polyline
|
||||
// instead of to the entire container (which is the default).
|
||||
@ -1155,8 +1205,11 @@ class InkAnnotationElement extends AnnotationElement {
|
||||
|
||||
class HighlightAnnotationElement extends AnnotationElement {
|
||||
constructor(parameters) {
|
||||
const isRenderable = !!(parameters.data.hasPopup ||
|
||||
parameters.data.title || parameters.data.contents);
|
||||
const isRenderable = !!(
|
||||
parameters.data.hasPopup ||
|
||||
parameters.data.title ||
|
||||
parameters.data.contents
|
||||
);
|
||||
super(parameters, isRenderable, /* ignoreBorder = */ true);
|
||||
}
|
||||
|
||||
@ -1168,7 +1221,7 @@ class HighlightAnnotationElement extends AnnotationElement {
|
||||
* @returns {HTMLSectionElement}
|
||||
*/
|
||||
render() {
|
||||
this.container.className = 'highlightAnnotation';
|
||||
this.container.className = "highlightAnnotation";
|
||||
|
||||
if (!this.data.hasPopup) {
|
||||
this._createPopup(this.container, null, this.data);
|
||||
@ -1179,8 +1232,11 @@ class HighlightAnnotationElement extends AnnotationElement {
|
||||
|
||||
class UnderlineAnnotationElement extends AnnotationElement {
|
||||
constructor(parameters) {
|
||||
const isRenderable = !!(parameters.data.hasPopup ||
|
||||
parameters.data.title || parameters.data.contents);
|
||||
const isRenderable = !!(
|
||||
parameters.data.hasPopup ||
|
||||
parameters.data.title ||
|
||||
parameters.data.contents
|
||||
);
|
||||
super(parameters, isRenderable, /* ignoreBorder = */ true);
|
||||
}
|
||||
|
||||
@ -1192,7 +1248,7 @@ class UnderlineAnnotationElement extends AnnotationElement {
|
||||
* @returns {HTMLSectionElement}
|
||||
*/
|
||||
render() {
|
||||
this.container.className = 'underlineAnnotation';
|
||||
this.container.className = "underlineAnnotation";
|
||||
|
||||
if (!this.data.hasPopup) {
|
||||
this._createPopup(this.container, null, this.data);
|
||||
@ -1203,8 +1259,11 @@ class UnderlineAnnotationElement extends AnnotationElement {
|
||||
|
||||
class SquigglyAnnotationElement extends AnnotationElement {
|
||||
constructor(parameters) {
|
||||
const isRenderable = !!(parameters.data.hasPopup ||
|
||||
parameters.data.title || parameters.data.contents);
|
||||
const isRenderable = !!(
|
||||
parameters.data.hasPopup ||
|
||||
parameters.data.title ||
|
||||
parameters.data.contents
|
||||
);
|
||||
super(parameters, isRenderable, /* ignoreBorder = */ true);
|
||||
}
|
||||
|
||||
@ -1216,7 +1275,7 @@ class SquigglyAnnotationElement extends AnnotationElement {
|
||||
* @returns {HTMLSectionElement}
|
||||
*/
|
||||
render() {
|
||||
this.container.className = 'squigglyAnnotation';
|
||||
this.container.className = "squigglyAnnotation";
|
||||
|
||||
if (!this.data.hasPopup) {
|
||||
this._createPopup(this.container, null, this.data);
|
||||
@ -1227,8 +1286,11 @@ class SquigglyAnnotationElement extends AnnotationElement {
|
||||
|
||||
class StrikeOutAnnotationElement extends AnnotationElement {
|
||||
constructor(parameters) {
|
||||
const isRenderable = !!(parameters.data.hasPopup ||
|
||||
parameters.data.title || parameters.data.contents);
|
||||
const isRenderable = !!(
|
||||
parameters.data.hasPopup ||
|
||||
parameters.data.title ||
|
||||
parameters.data.contents
|
||||
);
|
||||
super(parameters, isRenderable, /* ignoreBorder = */ true);
|
||||
}
|
||||
|
||||
@ -1240,7 +1302,7 @@ class StrikeOutAnnotationElement extends AnnotationElement {
|
||||
* @returns {HTMLSectionElement}
|
||||
*/
|
||||
render() {
|
||||
this.container.className = 'strikeoutAnnotation';
|
||||
this.container.className = "strikeoutAnnotation";
|
||||
|
||||
if (!this.data.hasPopup) {
|
||||
this._createPopup(this.container, null, this.data);
|
||||
@ -1251,8 +1313,11 @@ class StrikeOutAnnotationElement extends AnnotationElement {
|
||||
|
||||
class StampAnnotationElement extends AnnotationElement {
|
||||
constructor(parameters) {
|
||||
const isRenderable = !!(parameters.data.hasPopup ||
|
||||
parameters.data.title || parameters.data.contents);
|
||||
const isRenderable = !!(
|
||||
parameters.data.hasPopup ||
|
||||
parameters.data.title ||
|
||||
parameters.data.contents
|
||||
);
|
||||
super(parameters, isRenderable, /* ignoreBorder = */ true);
|
||||
}
|
||||
|
||||
@ -1264,7 +1329,7 @@ class StampAnnotationElement extends AnnotationElement {
|
||||
* @returns {HTMLSectionElement}
|
||||
*/
|
||||
render() {
|
||||
this.container.className = 'stampAnnotation';
|
||||
this.container.className = "stampAnnotation";
|
||||
|
||||
if (!this.data.hasPopup) {
|
||||
this._createPopup(this.container, null, this.data);
|
||||
@ -1277,12 +1342,12 @@ class FileAttachmentAnnotationElement extends AnnotationElement {
|
||||
constructor(parameters) {
|
||||
super(parameters, /* isRenderable = */ true);
|
||||
|
||||
const { filename, content, } = this.data.file;
|
||||
const { filename, content } = this.data.file;
|
||||
this.filename = getFilenameFromUrl(filename);
|
||||
this.content = content;
|
||||
|
||||
if (this.linkService.eventBus) {
|
||||
this.linkService.eventBus.dispatch('fileattachmentannotation', {
|
||||
this.linkService.eventBus.dispatch("fileattachmentannotation", {
|
||||
source: this,
|
||||
id: stringToPDFString(filename),
|
||||
filename,
|
||||
@ -1300,12 +1365,12 @@ class FileAttachmentAnnotationElement extends AnnotationElement {
|
||||
* @returns {HTMLSectionElement}
|
||||
*/
|
||||
render() {
|
||||
this.container.className = 'fileAttachmentAnnotation';
|
||||
this.container.className = "fileAttachmentAnnotation";
|
||||
|
||||
const trigger = document.createElement('div');
|
||||
const trigger = document.createElement("div");
|
||||
trigger.style.height = this.container.style.height;
|
||||
trigger.style.width = this.container.style.width;
|
||||
trigger.addEventListener('dblclick', this._download.bind(this));
|
||||
trigger.addEventListener("dblclick", this._download.bind(this));
|
||||
|
||||
if (!this.data.hasPopup && (this.data.title || this.data.contents)) {
|
||||
this._createPopup(this.container, trigger, this.data);
|
||||
@ -1323,10 +1388,10 @@ class FileAttachmentAnnotationElement extends AnnotationElement {
|
||||
*/
|
||||
_download() {
|
||||
if (!this.downloadManager) {
|
||||
warn('Download cannot be started due to unavailable download manager');
|
||||
warn("Download cannot be started due to unavailable download manager");
|
||||
return;
|
||||
}
|
||||
this.downloadManager.downloadData(this.content, this.filename, '');
|
||||
this.downloadManager.downloadData(this.content, this.filename, "");
|
||||
}
|
||||
}
|
||||
|
||||
@ -1363,7 +1428,7 @@ class AnnotationLayer {
|
||||
viewport: parameters.viewport,
|
||||
linkService: parameters.linkService,
|
||||
downloadManager: parameters.downloadManager,
|
||||
imageResourcesPath: parameters.imageResourcesPath || '',
|
||||
imageResourcesPath: parameters.imageResourcesPath || "",
|
||||
renderInteractiveForms: parameters.renderInteractiveForms || false,
|
||||
svgFactory: new DOMSVGFactory(),
|
||||
});
|
||||
@ -1383,16 +1448,16 @@ class AnnotationLayer {
|
||||
static update(parameters) {
|
||||
for (const data of parameters.annotations) {
|
||||
const element = parameters.div.querySelector(
|
||||
`[data-annotation-id="${data.id}"]`);
|
||||
`[data-annotation-id="${data.id}"]`
|
||||
);
|
||||
if (element) {
|
||||
element.style.transform =
|
||||
`matrix(${parameters.viewport.transform.join(',')})`;
|
||||
element.style.transform = `matrix(${parameters.viewport.transform.join(
|
||||
","
|
||||
)})`;
|
||||
}
|
||||
}
|
||||
parameters.div.removeAttribute('hidden');
|
||||
parameters.div.removeAttribute("hidden");
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
AnnotationLayer,
|
||||
};
|
||||
export { AnnotationLayer };
|
||||
|
1140
src/display/api.js
1140
src/display/api.js
File diff suppressed because it is too large
Load Diff
@ -14,11 +14,11 @@
|
||||
*/
|
||||
|
||||
let compatibilityParams = Object.create(null);
|
||||
if (typeof PDFJSDev === 'undefined' || PDFJSDev.test('GENERIC')) {
|
||||
const { isNodeJS, } = require('../shared/is_node');
|
||||
if (typeof PDFJSDev === "undefined" || PDFJSDev.test("GENERIC")) {
|
||||
const { isNodeJS } = require("../shared/is_node");
|
||||
|
||||
const userAgent =
|
||||
(typeof navigator !== 'undefined' && navigator.userAgent) || '';
|
||||
(typeof navigator !== "undefined" && navigator.userAgent) || "";
|
||||
const isIE = /Trident/.test(userAgent);
|
||||
const isIOSChrome = /CriOS/.test(userAgent);
|
||||
|
||||
@ -37,7 +37,7 @@ if (typeof PDFJSDev === 'undefined' || PDFJSDev.test('GENERIC')) {
|
||||
// Node.js is missing native support for `@font-face` and `Image`.
|
||||
if (isNodeJS) {
|
||||
compatibilityParams.disableFontFace = true;
|
||||
compatibilityParams.nativeImageDecoderSupport = 'none';
|
||||
compatibilityParams.nativeImageDecoderSupport = "none";
|
||||
}
|
||||
})();
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -31,7 +31,7 @@ function getFilenameFromContentDispositionHeader(contentDisposition) {
|
||||
let needsEncodingFixup = true;
|
||||
|
||||
// filename*=ext-value ("ext-value" from RFC 5987, referenced by RFC 6266).
|
||||
let tmp = toParamRegExp('filename\\*', 'i').exec(contentDisposition);
|
||||
let tmp = toParamRegExp("filename\\*", "i").exec(contentDisposition);
|
||||
if (tmp) {
|
||||
tmp = tmp[1];
|
||||
let filename = rfc2616unquote(tmp);
|
||||
@ -52,7 +52,7 @@ function getFilenameFromContentDispositionHeader(contentDisposition) {
|
||||
}
|
||||
|
||||
// filename=value (RFC 5987, section 4.1).
|
||||
tmp = toParamRegExp('filename', 'i').exec(contentDisposition);
|
||||
tmp = toParamRegExp("filename", "i").exec(contentDisposition);
|
||||
if (tmp) {
|
||||
tmp = tmp[1];
|
||||
let filename = rfc2616unquote(tmp);
|
||||
@ -65,14 +65,18 @@ function getFilenameFromContentDispositionHeader(contentDisposition) {
|
||||
// declarations...
|
||||
function toParamRegExp(attributePattern, flags) {
|
||||
return new RegExp(
|
||||
'(?:^|;)\\s*' + attributePattern + '\\s*=\\s*' +
|
||||
// Captures: value = token | quoted-string
|
||||
// (RFC 2616, section 3.6 and referenced by RFC 6266 4.1)
|
||||
'(' +
|
||||
"(?:^|;)\\s*" +
|
||||
attributePattern +
|
||||
"\\s*=\\s*" +
|
||||
// Captures: value = token | quoted-string
|
||||
// (RFC 2616, section 3.6 and referenced by RFC 6266 4.1)
|
||||
"(" +
|
||||
'[^";\\s][^;\\s]*' +
|
||||
'|' +
|
||||
"|" +
|
||||
'"(?:[^"\\\\]|\\\\"?)+"?' +
|
||||
')', flags);
|
||||
")",
|
||||
flags
|
||||
);
|
||||
}
|
||||
function textdecode(encoding, value) {
|
||||
if (encoding) {
|
||||
@ -80,9 +84,9 @@ function getFilenameFromContentDispositionHeader(contentDisposition) {
|
||||
return value;
|
||||
}
|
||||
try {
|
||||
let decoder = new TextDecoder(encoding, { fatal: true, });
|
||||
let decoder = new TextDecoder(encoding, { fatal: true });
|
||||
let bytes = Array.from(value, function(ch) {
|
||||
return ch.charCodeAt(0) & 0xFF;
|
||||
return ch.charCodeAt(0) & 0xff;
|
||||
});
|
||||
value = decoder.decode(new Uint8Array(bytes));
|
||||
needsEncodingFixup = false;
|
||||
@ -94,8 +98,7 @@ function getFilenameFromContentDispositionHeader(contentDisposition) {
|
||||
try {
|
||||
value = decodeURIComponent(escape(value));
|
||||
needsEncodingFixup = false;
|
||||
} catch (err) {
|
||||
}
|
||||
} catch (err) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -104,19 +107,20 @@ function getFilenameFromContentDispositionHeader(contentDisposition) {
|
||||
function fixupEncoding(value) {
|
||||
if (needsEncodingFixup && /[\x80-\xff]/.test(value)) {
|
||||
// Maybe multi-byte UTF-8.
|
||||
value = textdecode('utf-8', value);
|
||||
value = textdecode("utf-8", value);
|
||||
if (needsEncodingFixup) {
|
||||
// Try iso-8859-1 encoding.
|
||||
value = textdecode('iso-8859-1', value);
|
||||
value = textdecode("iso-8859-1", value);
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
function rfc2231getparam(contentDisposition) {
|
||||
let matches = [], match;
|
||||
let matches = [],
|
||||
match;
|
||||
// Iterate over all filename*n= and filename*n*= with n being an integer
|
||||
// of at least zero. Any non-zero number must not start with '0'.
|
||||
let iter = toParamRegExp('filename\\*((?!0\\d)\\d+)(\\*?)', 'ig');
|
||||
let iter = toParamRegExp("filename\\*((?!0\\d)\\d+)(\\*?)", "ig");
|
||||
while ((match = iter.exec(contentDisposition)) !== null) {
|
||||
let [, n, quot, part] = match;
|
||||
n = parseInt(n, 10);
|
||||
@ -145,7 +149,7 @@ function getFilenameFromContentDispositionHeader(contentDisposition) {
|
||||
}
|
||||
parts.push(part);
|
||||
}
|
||||
return parts.join('');
|
||||
return parts.join("");
|
||||
}
|
||||
function rfc2616unquote(value) {
|
||||
if (value.startsWith('"')) {
|
||||
@ -157,7 +161,7 @@ function getFilenameFromContentDispositionHeader(contentDisposition) {
|
||||
parts[i] = parts[i].slice(0, quotindex);
|
||||
parts.length = i + 1; // Truncates and stop the iteration.
|
||||
}
|
||||
parts[i] = parts[i].replace(/\\(.)/g, '$1');
|
||||
parts[i] = parts[i].replace(/\\(.)/g, "$1");
|
||||
}
|
||||
value = parts.join('"');
|
||||
}
|
||||
@ -165,7 +169,7 @@ function getFilenameFromContentDispositionHeader(contentDisposition) {
|
||||
}
|
||||
function rfc5987decode(extvalue) {
|
||||
// Decodes "ext-value" from RFC 5987.
|
||||
let encodingend = extvalue.indexOf('\'');
|
||||
let encodingend = extvalue.indexOf("'");
|
||||
if (encodingend === -1) {
|
||||
// Some servers send "filename*=" without encoding 'language' prefix,
|
||||
// e.g. in https://github.com/Rob--W/open-in-browser/issues/26
|
||||
@ -175,7 +179,7 @@ function getFilenameFromContentDispositionHeader(contentDisposition) {
|
||||
let encoding = extvalue.slice(0, encodingend);
|
||||
let langvalue = extvalue.slice(encodingend + 1);
|
||||
// Ignore language (RFC 5987 section 3.2.1, and RFC 6266 section 4.1 ).
|
||||
let value = langvalue.replace(/^[^']*'/, '');
|
||||
let value = langvalue.replace(/^[^']*'/, "");
|
||||
return textdecode(encoding, value);
|
||||
}
|
||||
function rfc2047decode(value) {
|
||||
@ -189,7 +193,7 @@ function getFilenameFromContentDispositionHeader(contentDisposition) {
|
||||
|
||||
// Firefox also decodes words even where RFC 2047 section 5 states:
|
||||
// "An 'encoded-word' MUST NOT appear within a 'quoted-string'."
|
||||
if (!value.startsWith('=?') || /[\x00-\x19\x80-\xff]/.test(value)) {
|
||||
if (!value.startsWith("=?") || /[\x00-\x19\x80-\xff]/.test(value)) {
|
||||
return value;
|
||||
}
|
||||
// RFC 2047, section 2.4
|
||||
@ -199,11 +203,12 @@ function getFilenameFromContentDispositionHeader(contentDisposition) {
|
||||
// encoding = q or b
|
||||
// encoded-text = any printable ASCII character other than ? or space.
|
||||
// ... but Firefox permits ? and space.
|
||||
return value.replace(/=\?([\w-]*)\?([QqBb])\?((?:[^?]|\?(?!=))*)\?=/g,
|
||||
return value.replace(
|
||||
/=\?([\w-]*)\?([QqBb])\?((?:[^?]|\?(?!=))*)\?=/g,
|
||||
function(_, charset, encoding, text) {
|
||||
if (encoding === 'q' || encoding === 'Q') {
|
||||
if (encoding === "q" || encoding === "Q") {
|
||||
// RFC 2047 section 4.2.
|
||||
text = text.replace(/_/g, ' ');
|
||||
text = text.replace(/_/g, " ");
|
||||
text = text.replace(/=([0-9a-fA-F]{2})/g, function(_, hex) {
|
||||
return String.fromCharCode(parseInt(hex, 16));
|
||||
});
|
||||
@ -211,15 +216,13 @@ function getFilenameFromContentDispositionHeader(contentDisposition) {
|
||||
} // else encoding is b or B - base64 (RFC 2047 section 4.1)
|
||||
try {
|
||||
text = atob(text);
|
||||
} catch (e) {
|
||||
}
|
||||
} catch (e) {}
|
||||
return textdecode(charset, text);
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return '';
|
||||
return "";
|
||||
}
|
||||
|
||||
export {
|
||||
getFilenameFromContentDispositionHeader,
|
||||
};
|
||||
export { getFilenameFromContentDispositionHeader };
|
||||
|
@ -15,20 +15,26 @@
|
||||
/* eslint no-var: error */
|
||||
|
||||
import {
|
||||
assert, BaseException, CMapCompressionType, isString, removeNullCharacters,
|
||||
stringToBytes, Util, warn
|
||||
} from '../shared/util';
|
||||
assert,
|
||||
BaseException,
|
||||
CMapCompressionType,
|
||||
isString,
|
||||
removeNullCharacters,
|
||||
stringToBytes,
|
||||
Util,
|
||||
warn,
|
||||
} from "../shared/util";
|
||||
|
||||
const DEFAULT_LINK_REL = 'noopener noreferrer nofollow';
|
||||
const SVG_NS = 'http://www.w3.org/2000/svg';
|
||||
const DEFAULT_LINK_REL = "noopener noreferrer nofollow";
|
||||
const SVG_NS = "http://www.w3.org/2000/svg";
|
||||
|
||||
class DOMCanvasFactory {
|
||||
create(width, height) {
|
||||
if (width <= 0 || height <= 0) {
|
||||
throw new Error('Invalid canvas size');
|
||||
throw new Error("Invalid canvas size");
|
||||
}
|
||||
const canvas = document.createElement('canvas');
|
||||
const context = canvas.getContext('2d');
|
||||
const canvas = document.createElement("canvas");
|
||||
const context = canvas.getContext("2d");
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
return {
|
||||
@ -39,10 +45,10 @@ class DOMCanvasFactory {
|
||||
|
||||
reset(canvasAndContext, width, height) {
|
||||
if (!canvasAndContext.canvas) {
|
||||
throw new Error('Canvas is not specified');
|
||||
throw new Error("Canvas is not specified");
|
||||
}
|
||||
if (width <= 0 || height <= 0) {
|
||||
throw new Error('Invalid canvas size');
|
||||
throw new Error("Invalid canvas size");
|
||||
}
|
||||
canvasAndContext.canvas.width = width;
|
||||
canvasAndContext.canvas.height = height;
|
||||
@ -50,7 +56,7 @@ class DOMCanvasFactory {
|
||||
|
||||
destroy(canvasAndContext) {
|
||||
if (!canvasAndContext.canvas) {
|
||||
throw new Error('Canvas is not specified');
|
||||
throw new Error("Canvas is not specified");
|
||||
}
|
||||
// Zeroing the width and height cause Firefox to release graphics
|
||||
// resources immediately, which can greatly reduce memory consumption.
|
||||
@ -62,50 +68,58 @@ class DOMCanvasFactory {
|
||||
}
|
||||
|
||||
class DOMCMapReaderFactory {
|
||||
constructor({ baseUrl = null, isCompressed = false, }) {
|
||||
constructor({ baseUrl = null, isCompressed = false }) {
|
||||
this.baseUrl = baseUrl;
|
||||
this.isCompressed = isCompressed;
|
||||
}
|
||||
|
||||
async fetch({ name, }) {
|
||||
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.');
|
||||
'the "cMapUrl" and "cMapPacked" API parameters are provided.'
|
||||
);
|
||||
}
|
||||
if (!name) {
|
||||
throw new Error('CMap name must be specified.');
|
||||
throw new Error("CMap name must be specified.");
|
||||
}
|
||||
const url = this.baseUrl + name + (this.isCompressed ? '.bcmap' : '');
|
||||
const compressionType = (this.isCompressed ? CMapCompressionType.BINARY :
|
||||
CMapCompressionType.NONE);
|
||||
const url = this.baseUrl + name + (this.isCompressed ? ".bcmap" : "");
|
||||
const compressionType = this.isCompressed
|
||||
? CMapCompressionType.BINARY
|
||||
: CMapCompressionType.NONE;
|
||||
|
||||
if ((typeof PDFJSDev !== 'undefined' && PDFJSDev.test('MOZCENTRAL')) ||
|
||||
(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 = stringToBytes(await response.text());
|
||||
}
|
||||
return { cMapData, compressionType, };
|
||||
}).catch((reason) => {
|
||||
throw new Error(`Unable to load ${this.isCompressed ? 'binary ' : ''}` +
|
||||
`CMap at: ${url}`);
|
||||
});
|
||||
if (
|
||||
(typeof PDFJSDev !== "undefined" && PDFJSDev.test("MOZCENTRAL")) ||
|
||||
(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 = stringToBytes(await response.text());
|
||||
}
|
||||
return { cMapData, compressionType };
|
||||
})
|
||||
.catch(reason => {
|
||||
throw new Error(
|
||||
`Unable to load ${this.isCompressed ? "binary " : ""}` +
|
||||
`CMap at: ${url}`
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
// The Fetch API is not supported.
|
||||
return new Promise((resolve, reject) => {
|
||||
const request = new XMLHttpRequest();
|
||||
request.open('GET', url, true);
|
||||
request.open("GET", url, true);
|
||||
|
||||
if (this.isCompressed) {
|
||||
request.responseType = 'arraybuffer';
|
||||
request.responseType = "arraybuffer";
|
||||
}
|
||||
request.onreadystatechange = () => {
|
||||
if (request.readyState !== XMLHttpRequest.DONE) {
|
||||
@ -119,7 +133,7 @@ class DOMCMapReaderFactory {
|
||||
cMapData = stringToBytes(request.responseText);
|
||||
}
|
||||
if (cMapData) {
|
||||
resolve({ cMapData, compressionType, });
|
||||
resolve({ cMapData, compressionType });
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -127,29 +141,31 @@ class DOMCMapReaderFactory {
|
||||
};
|
||||
|
||||
request.send(null);
|
||||
}).catch((reason) => {
|
||||
throw new Error(`Unable to load ${this.isCompressed ? 'binary ' : ''}` +
|
||||
`CMap at: ${url}`);
|
||||
}).catch(reason => {
|
||||
throw new Error(
|
||||
`Unable to load ${this.isCompressed ? "binary " : ""}` +
|
||||
`CMap at: ${url}`
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class DOMSVGFactory {
|
||||
create(width, height) {
|
||||
assert(width > 0 && height > 0, 'Invalid SVG dimensions');
|
||||
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);
|
||||
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) {
|
||||
assert(typeof type === 'string', 'Invalid SVG element type');
|
||||
assert(typeof type === "string", "Invalid SVG element type");
|
||||
|
||||
return document.createElementNS(SVG_NS, type);
|
||||
}
|
||||
@ -189,8 +205,14 @@ class PageViewport {
|
||||
/**
|
||||
* @param {PageViewportParameters}
|
||||
*/
|
||||
constructor({ viewBox, scale, rotation, offsetX = 0, offsetY = 0,
|
||||
dontFlip = false, }) {
|
||||
constructor({
|
||||
viewBox,
|
||||
scale,
|
||||
rotation,
|
||||
offsetX = 0,
|
||||
offsetY = 0,
|
||||
dontFlip = false,
|
||||
}) {
|
||||
this.viewBox = viewBox;
|
||||
this.scale = scale;
|
||||
this.rotation = rotation;
|
||||
@ -206,22 +228,35 @@ class PageViewport {
|
||||
rotation = rotation < 0 ? rotation + 360 : rotation;
|
||||
switch (rotation) {
|
||||
case 180:
|
||||
rotateA = -1; rotateB = 0; rotateC = 0; rotateD = 1;
|
||||
rotateA = -1;
|
||||
rotateB = 0;
|
||||
rotateC = 0;
|
||||
rotateD = 1;
|
||||
break;
|
||||
case 90:
|
||||
rotateA = 0; rotateB = 1; rotateC = 1; rotateD = 0;
|
||||
rotateA = 0;
|
||||
rotateB = 1;
|
||||
rotateC = 1;
|
||||
rotateD = 0;
|
||||
break;
|
||||
case 270:
|
||||
rotateA = 0; rotateB = -1; rotateC = -1; rotateD = 0;
|
||||
rotateA = 0;
|
||||
rotateB = -1;
|
||||
rotateC = -1;
|
||||
rotateD = 0;
|
||||
break;
|
||||
// case 0:
|
||||
default:
|
||||
rotateA = 1; rotateB = 0; rotateC = 0; rotateD = -1;
|
||||
rotateA = 1;
|
||||
rotateB = 0;
|
||||
rotateC = 0;
|
||||
rotateD = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (dontFlip) {
|
||||
rotateC = -rotateC; rotateD = -rotateD;
|
||||
rotateC = -rotateC;
|
||||
rotateD = -rotateD;
|
||||
}
|
||||
|
||||
let offsetCanvasX, offsetCanvasY;
|
||||
@ -246,7 +281,7 @@ class PageViewport {
|
||||
rotateC * scale,
|
||||
rotateD * scale,
|
||||
offsetCanvasX - rotateA * scale * centerX - rotateC * scale * centerY,
|
||||
offsetCanvasY - rotateB * scale * centerX - rotateD * scale * centerY
|
||||
offsetCanvasY - rotateB * scale * centerX - rotateD * scale * centerY,
|
||||
];
|
||||
|
||||
this.width = width;
|
||||
@ -258,8 +293,13 @@ class PageViewport {
|
||||
* @param {PageViewportCloneParameters} [params]
|
||||
* @returns {PageViewport} Cloned viewport.
|
||||
*/
|
||||
clone({ scale = this.scale, rotation = this.rotation, offsetX = this.offsetX,
|
||||
offsetY = this.offsetY, dontFlip = false, } = {}) {
|
||||
clone({
|
||||
scale = this.scale,
|
||||
rotation = this.rotation,
|
||||
offsetX = this.offsetX,
|
||||
offsetY = this.offsetY,
|
||||
dontFlip = false,
|
||||
} = {}) {
|
||||
return new PageViewport({
|
||||
viewBox: this.viewBox.slice(),
|
||||
scale,
|
||||
@ -343,50 +383,54 @@ const LinkTarget = {
|
||||
* @param {HTMLLinkElement} link - The link element.
|
||||
* @param {ExternalLinkParameters} params
|
||||
*/
|
||||
function addLinkAttributes(link, { url, target, rel, enabled = true, } = {}) {
|
||||
assert(url && typeof url === 'string',
|
||||
'addLinkAttributes: A valid "url" parameter must provided.');
|
||||
function addLinkAttributes(link, { url, target, rel, enabled = true } = {}) {
|
||||
assert(
|
||||
url && typeof url === "string",
|
||||
'addLinkAttributes: A valid "url" parameter must provided.'
|
||||
);
|
||||
|
||||
const urlNullRemoved = removeNullCharacters(url);
|
||||
if (enabled) {
|
||||
link.href = link.title = urlNullRemoved;
|
||||
} else {
|
||||
link.href = '';
|
||||
link.href = "";
|
||||
link.title = `Disabled: ${urlNullRemoved}`;
|
||||
link.onclick = () => {
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
let targetStr = ''; // LinkTarget.NONE
|
||||
let targetStr = ""; // LinkTarget.NONE
|
||||
switch (target) {
|
||||
case LinkTarget.NONE:
|
||||
break;
|
||||
case LinkTarget.SELF:
|
||||
targetStr = '_self';
|
||||
targetStr = "_self";
|
||||
break;
|
||||
case LinkTarget.BLANK:
|
||||
targetStr = '_blank';
|
||||
targetStr = "_blank";
|
||||
break;
|
||||
case LinkTarget.PARENT:
|
||||
targetStr = '_parent';
|
||||
targetStr = "_parent";
|
||||
break;
|
||||
case LinkTarget.TOP:
|
||||
targetStr = '_top';
|
||||
targetStr = "_top";
|
||||
break;
|
||||
}
|
||||
link.target = targetStr;
|
||||
|
||||
link.rel = (typeof rel === 'string' ? rel : DEFAULT_LINK_REL);
|
||||
link.rel = typeof rel === "string" ? rel : DEFAULT_LINK_REL;
|
||||
}
|
||||
|
||||
// Gets the file name from a given URL.
|
||||
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);
|
||||
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 {
|
||||
@ -407,9 +451,9 @@ class StatTimer {
|
||||
warn(`Timer has not been started for ${name}`);
|
||||
}
|
||||
this.times.push({
|
||||
'name': name,
|
||||
'start': this.started[name],
|
||||
'end': Date.now(),
|
||||
name,
|
||||
start: this.started[name],
|
||||
end: Date.now(),
|
||||
});
|
||||
// Remove timer from started so it can be called again.
|
||||
delete this.started[name];
|
||||
@ -417,7 +461,8 @@ class StatTimer {
|
||||
|
||||
toString() {
|
||||
// Find the longest name for padding purposes.
|
||||
let outBuf = [], longest = 0;
|
||||
let outBuf = [],
|
||||
longest = 0;
|
||||
for (const time of this.times) {
|
||||
const name = time.name;
|
||||
if (name.length > longest) {
|
||||
@ -428,21 +473,24 @@ class StatTimer {
|
||||
const duration = time.end - time.start;
|
||||
outBuf.push(`${time.name.padEnd(longest)} ${duration}ms\n`);
|
||||
}
|
||||
return outBuf.join('');
|
||||
return outBuf.join("");
|
||||
}
|
||||
}
|
||||
|
||||
function isFetchSupported() {
|
||||
return (typeof fetch !== 'undefined' &&
|
||||
typeof Response !== 'undefined' && 'body' in Response.prototype &&
|
||||
typeof ReadableStream !== 'undefined');
|
||||
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);
|
||||
const { protocol } = baseUrl ? new URL(url, baseUrl) : new URL(url);
|
||||
// The Fetch API only supports the http/https protocols, and not file/ftp.
|
||||
return (protocol === 'http:' || protocol === 'https:');
|
||||
return protocol === "http:" || protocol === "https:";
|
||||
} catch (ex) {
|
||||
return false; // `new URL()` will throw on incorrect data.
|
||||
}
|
||||
@ -450,7 +498,7 @@ function isValidFetchUrl(url, baseUrl) {
|
||||
|
||||
function loadScript(src) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const script = document.createElement('script');
|
||||
const script = document.createElement("script");
|
||||
script.src = src;
|
||||
|
||||
script.onload = resolve;
|
||||
@ -463,39 +511,42 @@ function loadScript(src) {
|
||||
|
||||
// Deprecated API function -- display regardless of the `verbosity` setting.
|
||||
function deprecated(details) {
|
||||
console.log('Deprecated API usage: ' + details);
|
||||
console.log("Deprecated API usage: " + details);
|
||||
}
|
||||
|
||||
function releaseImageResources(img) {
|
||||
assert(img instanceof Image, 'Invalid `img` parameter.');
|
||||
assert(img instanceof Image, "Invalid `img` parameter.");
|
||||
|
||||
const url = img.src;
|
||||
if (typeof url === 'string' && url.startsWith('blob:') &&
|
||||
URL.revokeObjectURL) {
|
||||
if (
|
||||
typeof url === "string" &&
|
||||
url.startsWith("blob:") &&
|
||||
URL.revokeObjectURL
|
||||
) {
|
||||
URL.revokeObjectURL(url);
|
||||
}
|
||||
img.removeAttribute('src');
|
||||
img.removeAttribute("src");
|
||||
}
|
||||
|
||||
let pdfDateStringRegex;
|
||||
|
||||
class PDFDateString {
|
||||
/**
|
||||
* Convert a PDF date string to a JavaScript `Date` object.
|
||||
*
|
||||
* The PDF date string format is described in section 7.9.4 of the official
|
||||
* PDF 32000-1:2008 specification. However, in the PDF 1.7 reference (sixth
|
||||
* edition) Adobe describes the same format including a trailing apostrophe.
|
||||
* This syntax in incorrect, but Adobe Acrobat creates PDF files that contain
|
||||
* them. We ignore all apostrophes as they are not necessary for date parsing.
|
||||
*
|
||||
* Moreover, Adobe Acrobat doesn't handle changing the date to universal time
|
||||
* and doesn't use the user's time zone (effectively ignoring the HH' and mm'
|
||||
* parts of the date string).
|
||||
*
|
||||
* @param {string} input
|
||||
* @returns {Date|null}
|
||||
*/
|
||||
/**
|
||||
* Convert a PDF date string to a JavaScript `Date` object.
|
||||
*
|
||||
* The PDF date string format is described in section 7.9.4 of the official
|
||||
* PDF 32000-1:2008 specification. However, in the PDF 1.7 reference (sixth
|
||||
* edition) Adobe describes the same format including a trailing apostrophe.
|
||||
* This syntax in incorrect, but Adobe Acrobat creates PDF files that contain
|
||||
* them. We ignore all apostrophes as they are not necessary for date parsing.
|
||||
*
|
||||
* Moreover, Adobe Acrobat doesn't handle changing the date to universal time
|
||||
* and doesn't use the user's time zone (effectively ignoring the HH' and mm'
|
||||
* parts of the date string).
|
||||
*
|
||||
* @param {string} input
|
||||
* @returns {Date|null}
|
||||
*/
|
||||
static toDateObject(input) {
|
||||
if (!input || !isString(input)) {
|
||||
return null;
|
||||
@ -504,18 +555,18 @@ class PDFDateString {
|
||||
// Lazily initialize the regular expression.
|
||||
if (!pdfDateStringRegex) {
|
||||
pdfDateStringRegex = new RegExp(
|
||||
'^D:' + // Prefix (required)
|
||||
'(\\d{4})' + // Year (required)
|
||||
'(\\d{2})?' + // Month (optional)
|
||||
'(\\d{2})?' + // Day (optional)
|
||||
'(\\d{2})?' + // Hour (optional)
|
||||
'(\\d{2})?' + // Minute (optional)
|
||||
'(\\d{2})?' + // Second (optional)
|
||||
'([Z|+|-])?' + // Universal time relation (optional)
|
||||
'(\\d{2})?' + // Offset hour (optional)
|
||||
'\'?' + // Splitting apostrophe (optional)
|
||||
'(\\d{2})?' + // Offset minute (optional)
|
||||
'\'?' // Trailing apostrophe (optional)
|
||||
"^D:" + // Prefix (required)
|
||||
"(\\d{4})" + // Year (required)
|
||||
"(\\d{2})?" + // Month (optional)
|
||||
"(\\d{2})?" + // Day (optional)
|
||||
"(\\d{2})?" + // Hour (optional)
|
||||
"(\\d{2})?" + // Minute (optional)
|
||||
"(\\d{2})?" + // Second (optional)
|
||||
"([Z|+|-])?" + // Universal time relation (optional)
|
||||
"(\\d{2})?" + // Offset hour (optional)
|
||||
"'?" + // Splitting apostrophe (optional)
|
||||
"(\\d{2})?" + // Offset minute (optional)
|
||||
"'?" // Trailing apostrophe (optional)
|
||||
);
|
||||
}
|
||||
|
||||
@ -531,29 +582,29 @@ class PDFDateString {
|
||||
// instead of 1 and 12, so we have to correct for that.
|
||||
const year = parseInt(matches[1], 10);
|
||||
let month = parseInt(matches[2], 10);
|
||||
month = (month >= 1 && month <= 12) ? month - 1 : 0;
|
||||
month = month >= 1 && month <= 12 ? month - 1 : 0;
|
||||
let day = parseInt(matches[3], 10);
|
||||
day = (day >= 1 && day <= 31) ? day : 1;
|
||||
day = day >= 1 && day <= 31 ? day : 1;
|
||||
let hour = parseInt(matches[4], 10);
|
||||
hour = (hour >= 0 && hour <= 23) ? hour : 0;
|
||||
hour = hour >= 0 && hour <= 23 ? hour : 0;
|
||||
let minute = parseInt(matches[5], 10);
|
||||
minute = (minute >= 0 && minute <= 59) ? minute : 0;
|
||||
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';
|
||||
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;
|
||||
offsetHour = offsetHour >= 0 && offsetHour <= 23 ? offsetHour : 0;
|
||||
let offsetMinute = parseInt(matches[9], 10) || 0;
|
||||
offsetMinute = (offsetMinute >= 0 && offsetMinute <= 59) ? offsetMinute : 0;
|
||||
offsetMinute = offsetMinute >= 0 && offsetMinute <= 59 ? offsetMinute : 0;
|
||||
|
||||
// Universal time relation 'Z' means that the local time is equal to the
|
||||
// universal time, whereas the relations '+'/'-' indicate that the local
|
||||
// time is later respectively earlier than the universal time. Every date
|
||||
// is normalized to universal time.
|
||||
if (universalTimeRelation === '-') {
|
||||
if (universalTimeRelation === "-") {
|
||||
hour += offsetHour;
|
||||
minute += offsetMinute;
|
||||
} else if (universalTimeRelation === '+') {
|
||||
} else if (universalTimeRelation === "+") {
|
||||
hour -= offsetHour;
|
||||
minute -= offsetMinute;
|
||||
}
|
||||
|
@ -15,21 +15,25 @@
|
||||
/* eslint no-var: error */
|
||||
|
||||
import {
|
||||
AbortException, assert, createPromiseCapability
|
||||
} from '../shared/util';
|
||||
AbortException,
|
||||
assert,
|
||||
createPromiseCapability,
|
||||
} from "../shared/util";
|
||||
import {
|
||||
createResponseStatusError, extractFilenameFromHeader,
|
||||
validateRangeRequestCapabilities, validateResponseStatus
|
||||
} from './network_utils';
|
||||
createResponseStatusError,
|
||||
extractFilenameFromHeader,
|
||||
validateRangeRequestCapabilities,
|
||||
validateResponseStatus,
|
||||
} from "./network_utils";
|
||||
|
||||
function createFetchOptions(headers, withCredentials, abortController) {
|
||||
return {
|
||||
method: 'GET',
|
||||
method: "GET",
|
||||
headers,
|
||||
signal: abortController && abortController.signal,
|
||||
mode: 'cors',
|
||||
credentials: withCredentials ? 'include' : 'same-origin',
|
||||
redirect: 'follow',
|
||||
mode: "cors",
|
||||
credentials: withCredentials ? "include" : "same-origin",
|
||||
redirect: "follow",
|
||||
};
|
||||
}
|
||||
|
||||
@ -37,7 +41,7 @@ function createHeaders(httpHeaders) {
|
||||
const headers = new Headers();
|
||||
for (const property in httpHeaders) {
|
||||
const value = httpHeaders[property];
|
||||
if (typeof value === 'undefined') {
|
||||
if (typeof value === "undefined") {
|
||||
continue;
|
||||
}
|
||||
headers.append(property, value);
|
||||
@ -57,7 +61,7 @@ class PDFFetchStream {
|
||||
}
|
||||
|
||||
get _progressiveDataLength() {
|
||||
return (this._fullRequestReader ? this._fullRequestReader._loaded : 0);
|
||||
return this._fullRequestReader ? this._fullRequestReader._loaded : 0;
|
||||
}
|
||||
|
||||
getFullReader() {
|
||||
@ -103,7 +107,7 @@ class PDFFetchStreamReader {
|
||||
this._disableRange = true;
|
||||
}
|
||||
|
||||
if (typeof AbortController !== 'undefined') {
|
||||
if (typeof AbortController !== "undefined") {
|
||||
this._abortController = new AbortController();
|
||||
}
|
||||
this._isStreamingSupported = !source.disableStream;
|
||||
@ -112,37 +116,47 @@ class PDFFetchStreamReader {
|
||||
this._headers = createHeaders(this._stream.httpHeaders);
|
||||
|
||||
const url = source.url;
|
||||
fetch(url, createFetchOptions(this._headers, this._withCredentials,
|
||||
this._abortController)).then((response) => {
|
||||
if (!validateResponseStatus(response.status)) {
|
||||
throw createResponseStatusError(response.status, url);
|
||||
}
|
||||
this._reader = response.body.getReader();
|
||||
this._headersCapability.resolve();
|
||||
fetch(
|
||||
url,
|
||||
createFetchOptions(
|
||||
this._headers,
|
||||
this._withCredentials,
|
||||
this._abortController
|
||||
)
|
||||
)
|
||||
.then(response => {
|
||||
if (!validateResponseStatus(response.status)) {
|
||||
throw createResponseStatusError(response.status, url);
|
||||
}
|
||||
this._reader = response.body.getReader();
|
||||
this._headersCapability.resolve();
|
||||
|
||||
const getResponseHeader = (name) => {
|
||||
return response.headers.get(name);
|
||||
};
|
||||
const { allowRangeRequests, suggestedLength, } =
|
||||
validateRangeRequestCapabilities({
|
||||
const getResponseHeader = name => {
|
||||
return response.headers.get(name);
|
||||
};
|
||||
const {
|
||||
allowRangeRequests,
|
||||
suggestedLength,
|
||||
} = validateRangeRequestCapabilities({
|
||||
getResponseHeader,
|
||||
isHttp: this._stream.isHttp,
|
||||
rangeChunkSize: this._rangeChunkSize,
|
||||
disableRange: this._disableRange,
|
||||
});
|
||||
|
||||
this._isRangeSupported = allowRangeRequests;
|
||||
// Setting right content length.
|
||||
this._contentLength = suggestedLength || this._contentLength;
|
||||
this._isRangeSupported = allowRangeRequests;
|
||||
// Setting right content length.
|
||||
this._contentLength = suggestedLength || this._contentLength;
|
||||
|
||||
this._filename = extractFilenameFromHeader(getResponseHeader);
|
||||
this._filename = extractFilenameFromHeader(getResponseHeader);
|
||||
|
||||
// We need to stop reading when range is supported and streaming is
|
||||
// disabled.
|
||||
if (!this._isStreamingSupported && this._isRangeSupported) {
|
||||
this.cancel(new AbortException('Streaming is disabled.'));
|
||||
}
|
||||
}).catch(this._headersCapability.reject);
|
||||
// We need to stop reading when range is supported and streaming is
|
||||
// disabled.
|
||||
if (!this._isStreamingSupported && this._isRangeSupported) {
|
||||
this.cancel(new AbortException("Streaming is disabled."));
|
||||
}
|
||||
})
|
||||
.catch(this._headersCapability.reject);
|
||||
|
||||
this.onProgress = null;
|
||||
}
|
||||
@ -169,9 +183,9 @@ class PDFFetchStreamReader {
|
||||
|
||||
async read() {
|
||||
await this._headersCapability.promise;
|
||||
const { value, done, } = await this._reader.read();
|
||||
const { value, done } = await this._reader.read();
|
||||
if (done) {
|
||||
return { value, done, };
|
||||
return { value, done };
|
||||
}
|
||||
this._loaded += value.byteLength;
|
||||
if (this.onProgress) {
|
||||
@ -181,7 +195,7 @@ class PDFFetchStreamReader {
|
||||
});
|
||||
}
|
||||
const buffer = new Uint8Array(value).buffer;
|
||||
return { value: buffer, done: false, };
|
||||
return { value: buffer, done: false };
|
||||
}
|
||||
|
||||
cancel(reason) {
|
||||
@ -205,16 +219,22 @@ class PDFFetchStreamRangeReader {
|
||||
this._readCapability = createPromiseCapability();
|
||||
this._isStreamingSupported = !source.disableStream;
|
||||
|
||||
if (typeof AbortController !== 'undefined') {
|
||||
if (typeof AbortController !== "undefined") {
|
||||
this._abortController = new AbortController();
|
||||
}
|
||||
|
||||
this._headers = createHeaders(this._stream.httpHeaders);
|
||||
this._headers.append('Range', `bytes=${begin}-${end - 1}`);
|
||||
this._headers.append("Range", `bytes=${begin}-${end - 1}`);
|
||||
|
||||
const url = source.url;
|
||||
fetch(url, createFetchOptions(this._headers, this._withCredentials,
|
||||
this._abortController)).then((response) => {
|
||||
fetch(
|
||||
url,
|
||||
createFetchOptions(
|
||||
this._headers,
|
||||
this._withCredentials,
|
||||
this._abortController
|
||||
)
|
||||
).then(response => {
|
||||
if (!validateResponseStatus(response.status)) {
|
||||
throw createResponseStatusError(response.status, url);
|
||||
}
|
||||
@ -231,16 +251,16 @@ class PDFFetchStreamRangeReader {
|
||||
|
||||
async read() {
|
||||
await this._readCapability.promise;
|
||||
const { value, done, } = await this._reader.read();
|
||||
const { value, done } = await this._reader.read();
|
||||
if (done) {
|
||||
return { value, done, };
|
||||
return { value, done };
|
||||
}
|
||||
this._loaded += value.byteLength;
|
||||
if (this.onProgress) {
|
||||
this.onProgress({ loaded: this._loaded, });
|
||||
this.onProgress({ loaded: this._loaded });
|
||||
}
|
||||
const buffer = new Uint8Array(value).buffer;
|
||||
return { value: buffer, done: false, };
|
||||
return { value: buffer, done: false };
|
||||
}
|
||||
|
||||
cancel(reason) {
|
||||
@ -253,6 +273,4 @@ class PDFFetchStreamRangeReader {
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
PDFFetchStream,
|
||||
};
|
||||
export { PDFFetchStream };
|
||||
|
@ -14,14 +14,20 @@
|
||||
*/
|
||||
|
||||
import {
|
||||
assert, bytesToString, isEvalSupported, shadow, string32, unreachable,
|
||||
UNSUPPORTED_FEATURES, warn
|
||||
} from '../shared/util';
|
||||
assert,
|
||||
bytesToString,
|
||||
isEvalSupported,
|
||||
shadow,
|
||||
string32,
|
||||
unreachable,
|
||||
UNSUPPORTED_FEATURES,
|
||||
warn,
|
||||
} from "../shared/util";
|
||||
|
||||
class BaseFontLoader {
|
||||
constructor({ docId, onUnsupportedFeature, }) {
|
||||
constructor({ docId, onUnsupportedFeature }) {
|
||||
if (this.constructor === BaseFontLoader) {
|
||||
unreachable('Cannot initialize BaseFontLoader.');
|
||||
unreachable("Cannot initialize BaseFontLoader.");
|
||||
}
|
||||
this.docId = docId;
|
||||
this._onUnsupportedFeature = onUnsupportedFeature;
|
||||
@ -38,10 +44,11 @@ class BaseFontLoader {
|
||||
insertRule(rule) {
|
||||
let styleElement = this.styleElement;
|
||||
if (!styleElement) {
|
||||
styleElement = this.styleElement = document.createElement('style');
|
||||
styleElement = this.styleElement = document.createElement("style");
|
||||
styleElement.id = `PDFJS_FONT_STYLE_TAG_${this.docId}`;
|
||||
document.documentElement.getElementsByTagName('head')[0].appendChild(
|
||||
styleElement);
|
||||
document.documentElement
|
||||
.getElementsByTagName("head")[0]
|
||||
.appendChild(styleElement);
|
||||
}
|
||||
|
||||
const styleSheet = styleElement.sheet;
|
||||
@ -75,7 +82,7 @@ class BaseFontLoader {
|
||||
try {
|
||||
await nativeFontFace.loaded;
|
||||
} catch (ex) {
|
||||
this._onUnsupportedFeature({ featureId: UNSUPPORTED_FEATURES.font, });
|
||||
this._onUnsupportedFeature({ featureId: UNSUPPORTED_FEATURES.font });
|
||||
warn(`Failed to load font '${nativeFontFace.family}': '${ex}'.`);
|
||||
|
||||
// When font loading failed, fall back to the built-in font renderer.
|
||||
@ -94,7 +101,7 @@ class BaseFontLoader {
|
||||
if (this.isSyncFontLoadingSupported) {
|
||||
return undefined; // The font was, synchronously, loaded.
|
||||
}
|
||||
return new Promise((resolve) => {
|
||||
return new Promise(resolve => {
|
||||
const request = this._queueLoadingCallback(resolve);
|
||||
this._prepareFontLoadEvent([rule], [font], request);
|
||||
});
|
||||
@ -103,251 +110,277 @@ class BaseFontLoader {
|
||||
}
|
||||
|
||||
_queueLoadingCallback(callback) {
|
||||
unreachable('Abstract method `_queueLoadingCallback`.');
|
||||
unreachable("Abstract method `_queueLoadingCallback`.");
|
||||
}
|
||||
|
||||
get isFontLoadingAPISupported() { // eslint-disable-line getter-return
|
||||
unreachable('Abstract method `isFontLoadingAPISupported`.');
|
||||
// eslint-disable-next-line getter-return
|
||||
get isFontLoadingAPISupported() {
|
||||
unreachable("Abstract method `isFontLoadingAPISupported`.");
|
||||
}
|
||||
|
||||
get isSyncFontLoadingSupported() { // eslint-disable-line getter-return
|
||||
unreachable('Abstract method `isSyncFontLoadingSupported`.');
|
||||
// eslint-disable-next-line getter-return
|
||||
get isSyncFontLoadingSupported() {
|
||||
unreachable("Abstract method `isSyncFontLoadingSupported`.");
|
||||
}
|
||||
|
||||
get _loadTestFont() { // eslint-disable-line getter-return
|
||||
unreachable('Abstract method `_loadTestFont`.');
|
||||
// eslint-disable-next-line getter-return
|
||||
get _loadTestFont() {
|
||||
unreachable("Abstract method `_loadTestFont`.");
|
||||
}
|
||||
|
||||
_prepareFontLoadEvent(rules, fontsToLoad, request) {
|
||||
unreachable('Abstract method `_prepareFontLoadEvent`.');
|
||||
unreachable("Abstract method `_prepareFontLoadEvent`.");
|
||||
}
|
||||
}
|
||||
|
||||
let FontLoader;
|
||||
if (typeof PDFJSDev !== 'undefined' && PDFJSDev.test('MOZCENTRAL')) {
|
||||
|
||||
FontLoader = class MozcentralFontLoader extends BaseFontLoader {
|
||||
get isFontLoadingAPISupported() {
|
||||
return shadow(this, 'isFontLoadingAPISupported',
|
||||
typeof document !== 'undefined' && !!document.fonts);
|
||||
}
|
||||
|
||||
get isSyncFontLoadingSupported() {
|
||||
return shadow(this, 'isSyncFontLoadingSupported', true);
|
||||
}
|
||||
};
|
||||
|
||||
} else { // PDFJSDev.test('CHROME || GENERIC')
|
||||
|
||||
FontLoader = class GenericFontLoader extends BaseFontLoader {
|
||||
constructor(docId) {
|
||||
super(docId);
|
||||
this.loadingContext = {
|
||||
requests: [],
|
||||
nextRequestId: 0,
|
||||
};
|
||||
this.loadTestFontId = 0;
|
||||
}
|
||||
|
||||
get isFontLoadingAPISupported() {
|
||||
let supported = (typeof document !== 'undefined' && !!document.fonts);
|
||||
|
||||
if ((typeof PDFJSDev === 'undefined' || !PDFJSDev.test('CHROME')) &&
|
||||
(supported && typeof navigator !== 'undefined')) {
|
||||
// The Firefox Font Loading API does not work with `mozPrintCallback`
|
||||
// prior to version 63; see https://bugzilla.mozilla.org/show_bug.cgi?id=1473742
|
||||
const m = /Mozilla\/5.0.*?rv:(\d+).*? Gecko/.exec(navigator.userAgent);
|
||||
if (m && m[1] < 63) {
|
||||
supported = false;
|
||||
}
|
||||
if (typeof PDFJSDev !== "undefined" && PDFJSDev.test("MOZCENTRAL")) {
|
||||
FontLoader = class MozcentralFontLoader extends BaseFontLoader {
|
||||
get isFontLoadingAPISupported() {
|
||||
return shadow(
|
||||
this,
|
||||
"isFontLoadingAPISupported",
|
||||
typeof document !== "undefined" && !!document.fonts
|
||||
);
|
||||
}
|
||||
return shadow(this, 'isFontLoadingAPISupported', supported);
|
||||
}
|
||||
|
||||
get isSyncFontLoadingSupported() {
|
||||
let supported = false;
|
||||
if (typeof PDFJSDev === 'undefined' || !PDFJSDev.test('CHROME')) {
|
||||
if (typeof navigator === 'undefined') {
|
||||
// Node.js - we can pretend that sync font loading is supported.
|
||||
supported = true;
|
||||
} else {
|
||||
// User agent string sniffing is bad, but there is no reliable way to
|
||||
// tell if the font is fully loaded and ready to be used with canvas.
|
||||
get isSyncFontLoadingSupported() {
|
||||
return shadow(this, "isSyncFontLoadingSupported", true);
|
||||
}
|
||||
};
|
||||
} else {
|
||||
// PDFJSDev.test('CHROME || GENERIC')
|
||||
|
||||
FontLoader = class GenericFontLoader extends BaseFontLoader {
|
||||
constructor(docId) {
|
||||
super(docId);
|
||||
this.loadingContext = {
|
||||
requests: [],
|
||||
nextRequestId: 0,
|
||||
};
|
||||
this.loadTestFontId = 0;
|
||||
}
|
||||
|
||||
get isFontLoadingAPISupported() {
|
||||
let supported = typeof document !== "undefined" && !!document.fonts;
|
||||
|
||||
if (
|
||||
(typeof PDFJSDev === "undefined" || !PDFJSDev.test("CHROME")) &&
|
||||
supported &&
|
||||
typeof navigator !== "undefined"
|
||||
) {
|
||||
// The Firefox Font Loading API does not work with `mozPrintCallback`
|
||||
// prior to version 63; see https://bugzilla.mozilla.org/show_bug.cgi?id=1473742
|
||||
const m = /Mozilla\/5.0.*?rv:(\d+).*? Gecko/.exec(navigator.userAgent);
|
||||
if (m && m[1] >= 14) {
|
||||
supported = true;
|
||||
if (m && m[1] < 63) {
|
||||
supported = false;
|
||||
}
|
||||
// TODO - other browsers...
|
||||
}
|
||||
return shadow(this, "isFontLoadingAPISupported", supported);
|
||||
}
|
||||
return shadow(this, 'isSyncFontLoadingSupported', supported);
|
||||
}
|
||||
|
||||
_queueLoadingCallback(callback) {
|
||||
function completeRequest() {
|
||||
assert(!request.done, 'completeRequest() cannot be called twice.');
|
||||
request.done = true;
|
||||
|
||||
// Sending all completed requests in order of how they were queued.
|
||||
while (context.requests.length > 0 && context.requests[0].done) {
|
||||
const otherRequest = context.requests.shift();
|
||||
setTimeout(otherRequest.callback, 0);
|
||||
get isSyncFontLoadingSupported() {
|
||||
let supported = false;
|
||||
if (typeof PDFJSDev === "undefined" || !PDFJSDev.test("CHROME")) {
|
||||
if (typeof navigator === "undefined") {
|
||||
// Node.js - we can pretend that sync font loading is supported.
|
||||
supported = true;
|
||||
} else {
|
||||
// User agent string sniffing is bad, but there is no reliable way to
|
||||
// tell if the font is fully loaded and ready to be used with canvas.
|
||||
const m = /Mozilla\/5.0.*?rv:(\d+).*? Gecko/.exec(
|
||||
navigator.userAgent
|
||||
);
|
||||
if (m && m[1] >= 14) {
|
||||
supported = true;
|
||||
}
|
||||
// TODO - other browsers...
|
||||
}
|
||||
}
|
||||
return shadow(this, "isSyncFontLoadingSupported", supported);
|
||||
}
|
||||
|
||||
const context = this.loadingContext;
|
||||
const request = {
|
||||
id: `pdfjs-font-loading-${context.nextRequestId++}`,
|
||||
done: false,
|
||||
complete: completeRequest,
|
||||
callback,
|
||||
};
|
||||
context.requests.push(request);
|
||||
return request;
|
||||
}
|
||||
_queueLoadingCallback(callback) {
|
||||
function completeRequest() {
|
||||
assert(!request.done, "completeRequest() cannot be called twice.");
|
||||
request.done = true;
|
||||
|
||||
get _loadTestFont() {
|
||||
const getLoadTestFont = function() {
|
||||
// This is a CFF font with 1 glyph for '.' that fills its entire width and
|
||||
// height.
|
||||
return atob(
|
||||
'T1RUTwALAIAAAwAwQ0ZGIDHtZg4AAAOYAAAAgUZGVE1lkzZwAAAEHAAAABxHREVGABQA' +
|
||||
'FQAABDgAAAAeT1MvMlYNYwkAAAEgAAAAYGNtYXABDQLUAAACNAAAAUJoZWFk/xVFDQAA' +
|
||||
'ALwAAAA2aGhlYQdkA+oAAAD0AAAAJGhtdHgD6AAAAAAEWAAAAAZtYXhwAAJQAAAAARgA' +
|
||||
'AAAGbmFtZVjmdH4AAAGAAAAAsXBvc3T/hgAzAAADeAAAACAAAQAAAAEAALZRFsRfDzz1' +
|
||||
'AAsD6AAAAADOBOTLAAAAAM4KHDwAAAAAA+gDIQAAAAgAAgAAAAAAAAABAAADIQAAAFoD' +
|
||||
'6AAAAAAD6AABAAAAAAAAAAAAAAAAAAAAAQAAUAAAAgAAAAQD6AH0AAUAAAKKArwAAACM' +
|
||||
'AooCvAAAAeAAMQECAAACAAYJAAAAAAAAAAAAAQAAAAAAAAAAAAAAAFBmRWQAwAAuAC4D' +
|
||||
'IP84AFoDIQAAAAAAAQAAAAAAAAAAACAAIAABAAAADgCuAAEAAAAAAAAAAQAAAAEAAAAA' +
|
||||
'AAEAAQAAAAEAAAAAAAIAAQAAAAEAAAAAAAMAAQAAAAEAAAAAAAQAAQAAAAEAAAAAAAUA' +
|
||||
'AQAAAAEAAAAAAAYAAQAAAAMAAQQJAAAAAgABAAMAAQQJAAEAAgABAAMAAQQJAAIAAgAB' +
|
||||
'AAMAAQQJAAMAAgABAAMAAQQJAAQAAgABAAMAAQQJAAUAAgABAAMAAQQJAAYAAgABWABY' +
|
||||
'AAAAAAAAAwAAAAMAAAAcAAEAAAAAADwAAwABAAAAHAAEACAAAAAEAAQAAQAAAC7//wAA' +
|
||||
'AC7////TAAEAAAAAAAABBgAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' +
|
||||
'AAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' +
|
||||
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' +
|
||||
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' +
|
||||
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' +
|
||||
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAAAAD/gwAyAAAAAQAAAAAAAAAAAAAAAAAA' +
|
||||
'AAABAAQEAAEBAQJYAAEBASH4DwD4GwHEAvgcA/gXBIwMAYuL+nz5tQXkD5j3CBLnEQAC' +
|
||||
'AQEBIVhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYAAABAQAADwACAQEEE/t3' +
|
||||
'Dov6fAH6fAT+fPp8+nwHDosMCvm1Cvm1DAz6fBQAAAAAAAABAAAAAMmJbzEAAAAAzgTj' +
|
||||
'FQAAAADOBOQpAAEAAAAAAAAADAAUAAQAAAABAAAAAgABAAAAAAAAAAAD6AAAAAAAAA==');
|
||||
};
|
||||
return shadow(this, '_loadTestFont', getLoadTestFont());
|
||||
}
|
||||
|
||||
_prepareFontLoadEvent(rules, fonts, request) {
|
||||
/** Hack begin */
|
||||
// There's currently no event when a font has finished downloading so the
|
||||
// following code is a dirty hack to 'guess' when a font is ready.
|
||||
// It's assumed fonts are loaded in order, so add a known test font after
|
||||
// the desired fonts and then test for the loading of that test font.
|
||||
|
||||
function int32(data, offset) {
|
||||
return (data.charCodeAt(offset) << 24) |
|
||||
(data.charCodeAt(offset + 1) << 16) |
|
||||
(data.charCodeAt(offset + 2) << 8) |
|
||||
(data.charCodeAt(offset + 3) & 0xff);
|
||||
}
|
||||
function spliceString(s, offset, remove, insert) {
|
||||
let chunk1 = s.substring(0, offset);
|
||||
let chunk2 = s.substring(offset + remove);
|
||||
return chunk1 + insert + chunk2;
|
||||
}
|
||||
let i, ii;
|
||||
|
||||
// The temporary canvas is used to determine if fonts are loaded.
|
||||
let canvas = document.createElement('canvas');
|
||||
canvas.width = 1;
|
||||
canvas.height = 1;
|
||||
let ctx = canvas.getContext('2d');
|
||||
|
||||
let called = 0;
|
||||
function isFontReady(name, callback) {
|
||||
called++;
|
||||
// With setTimeout clamping this gives the font ~100ms to load.
|
||||
if (called > 30) {
|
||||
warn('Load test font never loaded.');
|
||||
callback();
|
||||
return;
|
||||
// Sending all completed requests in order of how they were queued.
|
||||
while (context.requests.length > 0 && context.requests[0].done) {
|
||||
const otherRequest = context.requests.shift();
|
||||
setTimeout(otherRequest.callback, 0);
|
||||
}
|
||||
}
|
||||
ctx.font = '30px ' + name;
|
||||
ctx.fillText('.', 0, 20);
|
||||
let imageData = ctx.getImageData(0, 0, 1, 1);
|
||||
if (imageData.data[3] > 0) {
|
||||
callback();
|
||||
return;
|
||||
|
||||
const context = this.loadingContext;
|
||||
const request = {
|
||||
id: `pdfjs-font-loading-${context.nextRequestId++}`,
|
||||
done: false,
|
||||
complete: completeRequest,
|
||||
callback,
|
||||
};
|
||||
context.requests.push(request);
|
||||
return request;
|
||||
}
|
||||
|
||||
get _loadTestFont() {
|
||||
const getLoadTestFont = function() {
|
||||
// This is a CFF font with 1 glyph for '.' that fills its entire width
|
||||
// and height.
|
||||
return atob(
|
||||
"T1RUTwALAIAAAwAwQ0ZGIDHtZg4AAAOYAAAAgUZGVE1lkzZwAAAEHAAAABxHREVGABQA" +
|
||||
"FQAABDgAAAAeT1MvMlYNYwkAAAEgAAAAYGNtYXABDQLUAAACNAAAAUJoZWFk/xVFDQAA" +
|
||||
"ALwAAAA2aGhlYQdkA+oAAAD0AAAAJGhtdHgD6AAAAAAEWAAAAAZtYXhwAAJQAAAAARgA" +
|
||||
"AAAGbmFtZVjmdH4AAAGAAAAAsXBvc3T/hgAzAAADeAAAACAAAQAAAAEAALZRFsRfDzz1" +
|
||||
"AAsD6AAAAADOBOTLAAAAAM4KHDwAAAAAA+gDIQAAAAgAAgAAAAAAAAABAAADIQAAAFoD" +
|
||||
"6AAAAAAD6AABAAAAAAAAAAAAAAAAAAAAAQAAUAAAAgAAAAQD6AH0AAUAAAKKArwAAACM" +
|
||||
"AooCvAAAAeAAMQECAAACAAYJAAAAAAAAAAAAAQAAAAAAAAAAAAAAAFBmRWQAwAAuAC4D" +
|
||||
"IP84AFoDIQAAAAAAAQAAAAAAAAAAACAAIAABAAAADgCuAAEAAAAAAAAAAQAAAAEAAAAA" +
|
||||
"AAEAAQAAAAEAAAAAAAIAAQAAAAEAAAAAAAMAAQAAAAEAAAAAAAQAAQAAAAEAAAAAAAUA" +
|
||||
"AQAAAAEAAAAAAAYAAQAAAAMAAQQJAAAAAgABAAMAAQQJAAEAAgABAAMAAQQJAAIAAgAB" +
|
||||
"AAMAAQQJAAMAAgABAAMAAQQJAAQAAgABAAMAAQQJAAUAAgABAAMAAQQJAAYAAgABWABY" +
|
||||
"AAAAAAAAAwAAAAMAAAAcAAEAAAAAADwAAwABAAAAHAAEACAAAAAEAAQAAQAAAC7//wAA" +
|
||||
"AC7////TAAEAAAAAAAABBgAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +
|
||||
"AAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAAAAD/gwAyAAAAAQAAAAAAAAAAAAAAAAAA" +
|
||||
"AAABAAQEAAEBAQJYAAEBASH4DwD4GwHEAvgcA/gXBIwMAYuL+nz5tQXkD5j3CBLnEQAC" +
|
||||
"AQEBIVhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYAAABAQAADwACAQEEE/t3" +
|
||||
"Dov6fAH6fAT+fPp8+nwHDosMCvm1Cvm1DAz6fBQAAAAAAAABAAAAAMmJbzEAAAAAzgTj" +
|
||||
"FQAAAADOBOQpAAEAAAAAAAAADAAUAAQAAAABAAAAAgABAAAAAAAAAAAD6AAAAAAAAA=="
|
||||
);
|
||||
};
|
||||
return shadow(this, "_loadTestFont", getLoadTestFont());
|
||||
}
|
||||
|
||||
_prepareFontLoadEvent(rules, fonts, request) {
|
||||
/** Hack begin */
|
||||
// There's currently no event when a font has finished downloading so the
|
||||
// following code is a dirty hack to 'guess' when a font is ready.
|
||||
// It's assumed fonts are loaded in order, so add a known test font after
|
||||
// the desired fonts and then test for the loading of that test font.
|
||||
|
||||
function int32(data, offset) {
|
||||
return (
|
||||
(data.charCodeAt(offset) << 24) |
|
||||
(data.charCodeAt(offset + 1) << 16) |
|
||||
(data.charCodeAt(offset + 2) << 8) |
|
||||
(data.charCodeAt(offset + 3) & 0xff)
|
||||
);
|
||||
}
|
||||
setTimeout(isFontReady.bind(null, name, callback));
|
||||
function spliceString(s, offset, remove, insert) {
|
||||
let chunk1 = s.substring(0, offset);
|
||||
let chunk2 = s.substring(offset + remove);
|
||||
return chunk1 + insert + chunk2;
|
||||
}
|
||||
let i, ii;
|
||||
|
||||
// The temporary canvas is used to determine if fonts are loaded.
|
||||
let canvas = document.createElement("canvas");
|
||||
canvas.width = 1;
|
||||
canvas.height = 1;
|
||||
let ctx = canvas.getContext("2d");
|
||||
|
||||
let called = 0;
|
||||
function isFontReady(name, callback) {
|
||||
called++;
|
||||
// With setTimeout clamping this gives the font ~100ms to load.
|
||||
if (called > 30) {
|
||||
warn("Load test font never loaded.");
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
ctx.font = "30px " + name;
|
||||
ctx.fillText(".", 0, 20);
|
||||
let imageData = ctx.getImageData(0, 0, 1, 1);
|
||||
if (imageData.data[3] > 0) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
setTimeout(isFontReady.bind(null, name, callback));
|
||||
}
|
||||
|
||||
const loadTestFontId = `lt${Date.now()}${this.loadTestFontId++}`;
|
||||
// Chromium seems to cache fonts based on a hash of the actual font data,
|
||||
// so the font must be modified for each load test else it will appear to
|
||||
// be loaded already.
|
||||
// TODO: This could maybe be made faster by avoiding the btoa of the full
|
||||
// font by splitting it in chunks before hand and padding the font id.
|
||||
let data = this._loadTestFont;
|
||||
let COMMENT_OFFSET = 976; // has to be on 4 byte boundary (for checksum)
|
||||
data = spliceString(
|
||||
data,
|
||||
COMMENT_OFFSET,
|
||||
loadTestFontId.length,
|
||||
loadTestFontId
|
||||
);
|
||||
// CFF checksum is important for IE, adjusting it
|
||||
let CFF_CHECKSUM_OFFSET = 16;
|
||||
let XXXX_VALUE = 0x58585858; // the "comment" filled with 'X'
|
||||
let checksum = int32(data, CFF_CHECKSUM_OFFSET);
|
||||
for (i = 0, ii = loadTestFontId.length - 3; i < ii; i += 4) {
|
||||
checksum = (checksum - XXXX_VALUE + int32(loadTestFontId, i)) | 0;
|
||||
}
|
||||
if (i < loadTestFontId.length) {
|
||||
// align to 4 bytes boundary
|
||||
checksum =
|
||||
(checksum - XXXX_VALUE + int32(loadTestFontId + "XXX", i)) | 0;
|
||||
}
|
||||
data = spliceString(data, CFF_CHECKSUM_OFFSET, 4, string32(checksum));
|
||||
|
||||
const url = `url(data:font/opentype;base64,${btoa(data)});`;
|
||||
const rule = `@font-face {font-family:"${loadTestFontId}";src:${url}}`;
|
||||
this.insertRule(rule);
|
||||
|
||||
let names = [];
|
||||
for (i = 0, ii = fonts.length; i < ii; i++) {
|
||||
names.push(fonts[i].loadedName);
|
||||
}
|
||||
names.push(loadTestFontId);
|
||||
|
||||
let div = document.createElement("div");
|
||||
div.setAttribute(
|
||||
"style",
|
||||
"visibility: hidden;" +
|
||||
"width: 10px; height: 10px;" +
|
||||
"position: absolute; top: 0px; left: 0px;"
|
||||
);
|
||||
for (i = 0, ii = names.length; i < ii; ++i) {
|
||||
let span = document.createElement("span");
|
||||
span.textContent = "Hi";
|
||||
span.style.fontFamily = names[i];
|
||||
div.appendChild(span);
|
||||
}
|
||||
document.body.appendChild(div);
|
||||
|
||||
isFontReady(loadTestFontId, function() {
|
||||
document.body.removeChild(div);
|
||||
request.complete();
|
||||
});
|
||||
/** Hack end */
|
||||
}
|
||||
|
||||
const loadTestFontId = `lt${Date.now()}${this.loadTestFontId++}`;
|
||||
// Chromium seems to cache fonts based on a hash of the actual font data,
|
||||
// so the font must be modified for each load test else it will appear to
|
||||
// be loaded already.
|
||||
// TODO: This could maybe be made faster by avoiding the btoa of the full
|
||||
// font by splitting it in chunks before hand and padding the font id.
|
||||
let data = this._loadTestFont;
|
||||
let COMMENT_OFFSET = 976; // has to be on 4 byte boundary (for checksum)
|
||||
data = spliceString(data, COMMENT_OFFSET, loadTestFontId.length,
|
||||
loadTestFontId);
|
||||
// CFF checksum is important for IE, adjusting it
|
||||
let CFF_CHECKSUM_OFFSET = 16;
|
||||
let XXXX_VALUE = 0x58585858; // the "comment" filled with 'X'
|
||||
let checksum = int32(data, CFF_CHECKSUM_OFFSET);
|
||||
for (i = 0, ii = loadTestFontId.length - 3; i < ii; i += 4) {
|
||||
checksum = (checksum - XXXX_VALUE + int32(loadTestFontId, i)) | 0;
|
||||
}
|
||||
if (i < loadTestFontId.length) { // align to 4 bytes boundary
|
||||
checksum = (checksum - XXXX_VALUE + int32(loadTestFontId + 'XXX', i)) | 0;
|
||||
}
|
||||
data = spliceString(data, CFF_CHECKSUM_OFFSET, 4, string32(checksum));
|
||||
|
||||
const url = `url(data:font/opentype;base64,${btoa(data)});`;
|
||||
const rule = `@font-face {font-family:"${loadTestFontId}";src:${url}}`;
|
||||
this.insertRule(rule);
|
||||
|
||||
let names = [];
|
||||
for (i = 0, ii = fonts.length; i < ii; i++) {
|
||||
names.push(fonts[i].loadedName);
|
||||
}
|
||||
names.push(loadTestFontId);
|
||||
|
||||
let div = document.createElement('div');
|
||||
div.setAttribute('style', 'visibility: hidden;' +
|
||||
'width: 10px; height: 10px;' +
|
||||
'position: absolute; top: 0px; left: 0px;');
|
||||
for (i = 0, ii = names.length; i < ii; ++i) {
|
||||
let span = document.createElement('span');
|
||||
span.textContent = 'Hi';
|
||||
span.style.fontFamily = names[i];
|
||||
div.appendChild(span);
|
||||
}
|
||||
document.body.appendChild(div);
|
||||
|
||||
isFontReady(loadTestFontId, function() {
|
||||
document.body.removeChild(div);
|
||||
request.complete();
|
||||
});
|
||||
/** Hack end */
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
} // End of PDFJSDev.test('CHROME || GENERIC')
|
||||
|
||||
const IsEvalSupportedCached = {
|
||||
get value() {
|
||||
return shadow(this, 'value', isEvalSupported());
|
||||
return shadow(this, "value", isEvalSupported());
|
||||
},
|
||||
};
|
||||
|
||||
class FontFaceObject {
|
||||
constructor(translatedData, { isEvalSupported = true,
|
||||
disableFontFace = false,
|
||||
ignoreErrors = false,
|
||||
onUnsupportedFeature = null,
|
||||
fontRegistry = null, }) {
|
||||
constructor(
|
||||
translatedData,
|
||||
{
|
||||
isEvalSupported = true,
|
||||
disableFontFace = false,
|
||||
ignoreErrors = false,
|
||||
onUnsupportedFeature = null,
|
||||
fontRegistry = null,
|
||||
}
|
||||
) {
|
||||
this.compiledGlyphs = Object.create(null);
|
||||
// importing translated data
|
||||
for (let i in translatedData) {
|
||||
@ -394,53 +427,51 @@ class FontFaceObject {
|
||||
|
||||
let cmds, current;
|
||||
try {
|
||||
cmds = objs.get(this.loadedName + '_path_' + character);
|
||||
cmds = objs.get(this.loadedName + "_path_" + character);
|
||||
} catch (ex) {
|
||||
if (!this.ignoreErrors) {
|
||||
throw ex;
|
||||
}
|
||||
if (this._onUnsupportedFeature) {
|
||||
this._onUnsupportedFeature({ featureId: UNSUPPORTED_FEATURES.font, });
|
||||
this._onUnsupportedFeature({ featureId: UNSUPPORTED_FEATURES.font });
|
||||
}
|
||||
warn(`getPathGenerator - ignoring character: "${ex}".`);
|
||||
|
||||
return this.compiledGlyphs[character] = function(c, size) {
|
||||
return (this.compiledGlyphs[character] = function(c, size) {
|
||||
// No-op function, to allow rendering to continue.
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
// If we can, compile cmds into JS for MAXIMUM SPEED...
|
||||
if (this.isEvalSupported && IsEvalSupportedCached.value) {
|
||||
let args, js = '';
|
||||
let args,
|
||||
js = "";
|
||||
for (let i = 0, ii = cmds.length; i < ii; i++) {
|
||||
current = cmds[i];
|
||||
|
||||
if (current.args !== undefined) {
|
||||
args = current.args.join(',');
|
||||
args = current.args.join(",");
|
||||
} else {
|
||||
args = '';
|
||||
args = "";
|
||||
}
|
||||
js += 'c.' + current.cmd + '(' + args + ');\n';
|
||||
js += "c." + current.cmd + "(" + args + ");\n";
|
||||
}
|
||||
// eslint-disable-next-line no-new-func
|
||||
return this.compiledGlyphs[character] = new Function('c', 'size', js);
|
||||
return (this.compiledGlyphs[character] = new Function("c", "size", js));
|
||||
}
|
||||
// ... but fall back on using Function.prototype.apply() if we're
|
||||
// blocked from using eval() for whatever reason (like CSP policies).
|
||||
return this.compiledGlyphs[character] = function(c, size) {
|
||||
return (this.compiledGlyphs[character] = function(c, size) {
|
||||
for (let i = 0, ii = cmds.length; i < ii; i++) {
|
||||
current = cmds[i];
|
||||
|
||||
if (current.cmd === 'scale') {
|
||||
if (current.cmd === "scale") {
|
||||
current.args = [size, -size];
|
||||
}
|
||||
c[current.cmd].apply(c, current.args);
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
FontFaceObject,
|
||||
FontLoader,
|
||||
};
|
||||
export { FontFaceObject, FontLoader };
|
||||
|
@ -13,12 +13,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { assert } from '../shared/util';
|
||||
import { SimpleXMLParser } from './xml_parser';
|
||||
import { assert } from "../shared/util";
|
||||
import { SimpleXMLParser } from "./xml_parser";
|
||||
|
||||
class Metadata {
|
||||
constructor(data) {
|
||||
assert(typeof data === 'string', 'Metadata: input is not a string');
|
||||
assert(typeof data === "string", "Metadata: input is not a string");
|
||||
|
||||
// Ghostscript may produce invalid metadata, so try to repair that first.
|
||||
data = this._repair(data);
|
||||
@ -36,66 +36,74 @@ class Metadata {
|
||||
|
||||
_repair(data) {
|
||||
// Start by removing any "junk" before the first tag (see issue 10395).
|
||||
return data.replace(/^([^<]+)/, '').replace(/>\\376\\377([^<]+)/g,
|
||||
function(all, codes) {
|
||||
let bytes = codes.replace(/\\([0-3])([0-7])([0-7])/g,
|
||||
function(code, d1, d2, d3) {
|
||||
return String.fromCharCode(d1 * 64 + d2 * 8 + d3 * 1);
|
||||
}).replace(/&(amp|apos|gt|lt|quot);/g, function(str, name) {
|
||||
switch (name) {
|
||||
case 'amp':
|
||||
return '&';
|
||||
case 'apos':
|
||||
return '\'';
|
||||
case 'gt':
|
||||
return '>';
|
||||
case 'lt':
|
||||
return '<';
|
||||
case 'quot':
|
||||
return '\"';
|
||||
return data
|
||||
.replace(/^([^<]+)/, "")
|
||||
.replace(/>\\376\\377([^<]+)/g, function(all, codes) {
|
||||
let bytes = codes
|
||||
.replace(/\\([0-3])([0-7])([0-7])/g, function(code, d1, d2, d3) {
|
||||
return String.fromCharCode(d1 * 64 + d2 * 8 + d3 * 1);
|
||||
})
|
||||
.replace(/&(amp|apos|gt|lt|quot);/g, function(str, name) {
|
||||
switch (name) {
|
||||
case "amp":
|
||||
return "&";
|
||||
case "apos":
|
||||
return "'";
|
||||
case "gt":
|
||||
return ">";
|
||||
case "lt":
|
||||
return "<";
|
||||
case "quot":
|
||||
return '"';
|
||||
}
|
||||
throw new Error(`_repair: ${name} isn't defined.`);
|
||||
});
|
||||
|
||||
let chars = "";
|
||||
for (let i = 0, ii = bytes.length; i < ii; i += 2) {
|
||||
let code = bytes.charCodeAt(i) * 256 + bytes.charCodeAt(i + 1);
|
||||
if (
|
||||
code >= 32 &&
|
||||
code < 127 &&
|
||||
code !== 60 &&
|
||||
code !== 62 &&
|
||||
code !== 38
|
||||
) {
|
||||
chars += String.fromCharCode(code);
|
||||
} else {
|
||||
chars += "&#x" + (0x10000 + code).toString(16).substring(1) + ";";
|
||||
}
|
||||
}
|
||||
throw new Error(`_repair: ${name} isn't defined.`);
|
||||
|
||||
return ">" + chars;
|
||||
});
|
||||
|
||||
let chars = '';
|
||||
for (let i = 0, ii = bytes.length; i < ii; i += 2) {
|
||||
let code = bytes.charCodeAt(i) * 256 + bytes.charCodeAt(i + 1);
|
||||
if (code >= 32 && code < 127 && code !== 60 && code !== 62 &&
|
||||
code !== 38) {
|
||||
chars += String.fromCharCode(code);
|
||||
} else {
|
||||
chars += '&#x' + (0x10000 + code).toString(16).substring(1) + ';';
|
||||
}
|
||||
}
|
||||
|
||||
return '>' + chars;
|
||||
});
|
||||
}
|
||||
|
||||
_parse(xmlDocument) {
|
||||
let rdf = xmlDocument.documentElement;
|
||||
|
||||
if (rdf.nodeName.toLowerCase() !== 'rdf:rdf') { // Wrapped in <xmpmeta>
|
||||
if (rdf.nodeName.toLowerCase() !== "rdf:rdf") {
|
||||
// Wrapped in <xmpmeta>
|
||||
rdf = rdf.firstChild;
|
||||
while (rdf && rdf.nodeName.toLowerCase() !== 'rdf:rdf') {
|
||||
while (rdf && rdf.nodeName.toLowerCase() !== "rdf:rdf") {
|
||||
rdf = rdf.nextSibling;
|
||||
}
|
||||
}
|
||||
|
||||
let nodeName = rdf ? rdf.nodeName.toLowerCase() : null;
|
||||
if (!rdf || nodeName !== 'rdf:rdf' || !rdf.hasChildNodes()) {
|
||||
if (!rdf || nodeName !== "rdf:rdf" || !rdf.hasChildNodes()) {
|
||||
return;
|
||||
}
|
||||
|
||||
let children = rdf.childNodes;
|
||||
for (let i = 0, ii = children.length; i < ii; i++) {
|
||||
let desc = children[i];
|
||||
if (desc.nodeName.toLowerCase() !== 'rdf:description') {
|
||||
if (desc.nodeName.toLowerCase() !== "rdf:description") {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (let j = 0, jj = desc.childNodes.length; j < jj; j++) {
|
||||
if (desc.childNodes[j].nodeName.toLowerCase() !== '#text') {
|
||||
if (desc.childNodes[j].nodeName.toLowerCase() !== "#text") {
|
||||
let entry = desc.childNodes[j];
|
||||
let name = entry.nodeName.toLowerCase();
|
||||
|
||||
@ -107,7 +115,7 @@ class Metadata {
|
||||
|
||||
get(name) {
|
||||
const data = this._metadata[name];
|
||||
return (typeof data !== 'undefined' ? data : null);
|
||||
return typeof data !== "undefined" ? data : null;
|
||||
}
|
||||
|
||||
getAll() {
|
||||
@ -115,10 +123,8 @@ class Metadata {
|
||||
}
|
||||
|
||||
has(name) {
|
||||
return typeof this._metadata[name] !== 'undefined';
|
||||
return typeof this._metadata[name] !== "undefined";
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
Metadata,
|
||||
};
|
||||
export { Metadata };
|
||||
|
@ -14,15 +14,18 @@
|
||||
*/
|
||||
/* eslint no-var: error */
|
||||
|
||||
import { assert, createPromiseCapability, stringToBytes } from '../shared/util';
|
||||
import { assert, createPromiseCapability, stringToBytes } from "../shared/util";
|
||||
import {
|
||||
createResponseStatusError, extractFilenameFromHeader,
|
||||
validateRangeRequestCapabilities
|
||||
} from './network_utils';
|
||||
createResponseStatusError,
|
||||
extractFilenameFromHeader,
|
||||
validateRangeRequestCapabilities,
|
||||
} from "./network_utils";
|
||||
|
||||
if (typeof PDFJSDev !== 'undefined' && PDFJSDev.test('FIREFOX || MOZCENTRAL')) {
|
||||
throw new Error('Module "./network" shall not ' +
|
||||
'be used with FIREFOX or MOZCENTRAL build.');
|
||||
if (typeof PDFJSDev !== "undefined" && PDFJSDev.test("FIREFOX || MOZCENTRAL")) {
|
||||
throw new Error(
|
||||
'Module "./network" shall not ' +
|
||||
"be used with FIREFOX or MOZCENTRAL build."
|
||||
);
|
||||
}
|
||||
|
||||
const OK_RESPONSE = 200;
|
||||
@ -30,7 +33,7 @@ const PARTIAL_CONTENT_RESPONSE = 206;
|
||||
|
||||
function getArrayBuffer(xhr) {
|
||||
const data = xhr.response;
|
||||
if (typeof data !== 'string') {
|
||||
if (typeof data !== "string") {
|
||||
return data;
|
||||
}
|
||||
const array = stringToBytes(data);
|
||||
@ -44,7 +47,8 @@ class NetworkManager {
|
||||
this.isHttp = /^https?:/i.test(url);
|
||||
this.httpHeaders = (this.isHttp && args.httpHeaders) || {};
|
||||
this.withCredentials = args.withCredentials || false;
|
||||
this.getXhr = args.getXhr ||
|
||||
this.getXhr =
|
||||
args.getXhr ||
|
||||
function NetworkManager_getXhr() {
|
||||
return new XMLHttpRequest();
|
||||
};
|
||||
@ -71,26 +75,26 @@ class NetworkManager {
|
||||
request(args) {
|
||||
const xhr = this.getXhr();
|
||||
const xhrId = this.currXhrId++;
|
||||
const pendingRequest = this.pendingRequests[xhrId] = {
|
||||
const pendingRequest = (this.pendingRequests[xhrId] = {
|
||||
xhr,
|
||||
};
|
||||
});
|
||||
|
||||
xhr.open('GET', this.url);
|
||||
xhr.open("GET", this.url);
|
||||
xhr.withCredentials = this.withCredentials;
|
||||
for (const property in this.httpHeaders) {
|
||||
const value = this.httpHeaders[property];
|
||||
if (typeof value === 'undefined') {
|
||||
if (typeof value === "undefined") {
|
||||
continue;
|
||||
}
|
||||
xhr.setRequestHeader(property, value);
|
||||
}
|
||||
if (this.isHttp && 'begin' in args && 'end' in args) {
|
||||
xhr.setRequestHeader('Range', `bytes=${args.begin}-${args.end - 1}`);
|
||||
if (this.isHttp && "begin" in args && "end" in args) {
|
||||
xhr.setRequestHeader("Range", `bytes=${args.begin}-${args.end - 1}`);
|
||||
pendingRequest.expectedStatus = PARTIAL_CONTENT_RESPONSE;
|
||||
} else {
|
||||
pendingRequest.expectedStatus = OK_RESPONSE;
|
||||
}
|
||||
xhr.responseType = 'arraybuffer';
|
||||
xhr.responseType = "arraybuffer";
|
||||
|
||||
if (args.onError) {
|
||||
xhr.onerror = function(evt) {
|
||||
@ -163,8 +167,10 @@ class NetworkManager {
|
||||
xhrStatus === OK_RESPONSE &&
|
||||
pendingRequest.expectedStatus === PARTIAL_CONTENT_RESPONSE;
|
||||
|
||||
if (!ok_response_on_range_request &&
|
||||
xhrStatus !== pendingRequest.expectedStatus) {
|
||||
if (
|
||||
!ok_response_on_range_request &&
|
||||
xhrStatus !== pendingRequest.expectedStatus
|
||||
) {
|
||||
if (pendingRequest.onError) {
|
||||
pendingRequest.onError(xhr.status);
|
||||
}
|
||||
@ -173,7 +179,7 @@ class NetworkManager {
|
||||
|
||||
const chunk = getArrayBuffer(xhr);
|
||||
if (xhrStatus === PARTIAL_CONTENT_RESPONSE) {
|
||||
const rangeHeader = xhr.getResponseHeader('Content-Range');
|
||||
const rangeHeader = xhr.getResponseHeader("Content-Range");
|
||||
const matches = /bytes (\d+)-(\d+)\/(\d+)/.exec(rangeHeader);
|
||||
pendingRequest.onDone({
|
||||
begin: parseInt(matches[1], 10),
|
||||
@ -239,14 +245,19 @@ class PDFNetworkStream {
|
||||
|
||||
getFullReader() {
|
||||
assert(!this._fullRequestReader);
|
||||
this._fullRequestReader =
|
||||
new PDFNetworkStreamFullRequestReader(this._manager, this._source);
|
||||
this._fullRequestReader = new PDFNetworkStreamFullRequestReader(
|
||||
this._manager,
|
||||
this._source
|
||||
);
|
||||
return this._fullRequestReader;
|
||||
}
|
||||
|
||||
getRangeReader(begin, end) {
|
||||
const reader = new PDFNetworkStreamRangeRequestReader(this._manager,
|
||||
begin, end);
|
||||
const reader = new PDFNetworkStreamRangeRequestReader(
|
||||
this._manager,
|
||||
begin,
|
||||
end
|
||||
);
|
||||
reader.onClosed = this._onRangeRequestReaderClosed.bind(this);
|
||||
this._rangeRequestReaders.push(reader);
|
||||
return reader;
|
||||
@ -300,16 +311,18 @@ class PDFNetworkStreamFullRequestReader {
|
||||
const fullRequestXhrId = this._fullRequestId;
|
||||
const fullRequestXhr = this._manager.getRequestXhr(fullRequestXhrId);
|
||||
|
||||
const getResponseHeader = (name) => {
|
||||
const getResponseHeader = name => {
|
||||
return fullRequestXhr.getResponseHeader(name);
|
||||
};
|
||||
const { allowRangeRequests, suggestedLength, } =
|
||||
validateRangeRequestCapabilities({
|
||||
getResponseHeader,
|
||||
isHttp: this._manager.isHttp,
|
||||
rangeChunkSize: this._rangeChunkSize,
|
||||
disableRange: this._disableRange,
|
||||
});
|
||||
const {
|
||||
allowRangeRequests,
|
||||
suggestedLength,
|
||||
} = validateRangeRequestCapabilities({
|
||||
getResponseHeader,
|
||||
isHttp: this._manager.isHttp,
|
||||
rangeChunkSize: this._rangeChunkSize,
|
||||
disableRange: this._disableRange,
|
||||
});
|
||||
|
||||
if (allowRangeRequests) {
|
||||
this._isRangeSupported = true;
|
||||
@ -334,7 +347,7 @@ class PDFNetworkStreamFullRequestReader {
|
||||
if (args) {
|
||||
if (this._requests.length > 0) {
|
||||
const requestCapability = this._requests.shift();
|
||||
requestCapability.resolve({ value: args.chunk, done: false, });
|
||||
requestCapability.resolve({ value: args.chunk, done: false });
|
||||
} else {
|
||||
this._cachedChunks.push(args.chunk);
|
||||
}
|
||||
@ -344,7 +357,7 @@ class PDFNetworkStreamFullRequestReader {
|
||||
return;
|
||||
}
|
||||
this._requests.forEach(function(requestCapability) {
|
||||
requestCapability.resolve({ value: undefined, done: true, });
|
||||
requestCapability.resolve({ value: undefined, done: true });
|
||||
});
|
||||
this._requests = [];
|
||||
}
|
||||
@ -396,10 +409,10 @@ class PDFNetworkStreamFullRequestReader {
|
||||
}
|
||||
if (this._cachedChunks.length > 0) {
|
||||
const chunk = this._cachedChunks.shift();
|
||||
return { value: chunk, done: false, };
|
||||
return { value: chunk, done: false };
|
||||
}
|
||||
if (this._done) {
|
||||
return { value: undefined, done: true, };
|
||||
return { value: undefined, done: true };
|
||||
}
|
||||
const requestCapability = createPromiseCapability();
|
||||
this._requests.push(requestCapability);
|
||||
@ -409,8 +422,8 @@ class PDFNetworkStreamFullRequestReader {
|
||||
cancel(reason) {
|
||||
this._done = true;
|
||||
this._headersReceivedCapability.reject(reason);
|
||||
this._requests.forEach(function (requestCapability) {
|
||||
requestCapability.resolve({ value: undefined, done: true, });
|
||||
this._requests.forEach(function(requestCapability) {
|
||||
requestCapability.resolve({ value: undefined, done: true });
|
||||
});
|
||||
this._requests = [];
|
||||
if (this._manager.isPendingRequest(this._fullRequestId)) {
|
||||
@ -447,13 +460,13 @@ class PDFNetworkStreamRangeRequestReader {
|
||||
const chunk = data.chunk;
|
||||
if (this._requests.length > 0) {
|
||||
const requestCapability = this._requests.shift();
|
||||
requestCapability.resolve({ value: chunk, done: false, });
|
||||
requestCapability.resolve({ value: chunk, done: false });
|
||||
} else {
|
||||
this._queuedChunk = chunk;
|
||||
}
|
||||
this._done = true;
|
||||
this._requests.forEach(function(requestCapability) {
|
||||
requestCapability.resolve({ value: undefined, done: true, });
|
||||
requestCapability.resolve({ value: undefined, done: true });
|
||||
});
|
||||
this._requests = [];
|
||||
this._close();
|
||||
@ -475,10 +488,10 @@ class PDFNetworkStreamRangeRequestReader {
|
||||
if (this._queuedChunk !== null) {
|
||||
const chunk = this._queuedChunk;
|
||||
this._queuedChunk = null;
|
||||
return { value: chunk, done: false, };
|
||||
return { value: chunk, done: false };
|
||||
}
|
||||
if (this._done) {
|
||||
return { value: undefined, done: true, };
|
||||
return { value: undefined, done: true };
|
||||
}
|
||||
const requestCapability = createPromiseCapability();
|
||||
this._requests.push(requestCapability);
|
||||
@ -487,8 +500,8 @@ class PDFNetworkStreamRangeRequestReader {
|
||||
|
||||
cancel(reason) {
|
||||
this._done = true;
|
||||
this._requests.forEach(function (requestCapability) {
|
||||
requestCapability.resolve({ value: undefined, done: true, });
|
||||
this._requests.forEach(function(requestCapability) {
|
||||
requestCapability.resolve({ value: undefined, done: true });
|
||||
});
|
||||
this._requests = [];
|
||||
if (this._manager.isPendingRequest(this._requestId)) {
|
||||
@ -498,6 +511,4 @@ class PDFNetworkStreamRangeRequestReader {
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
PDFNetworkStream,
|
||||
};
|
||||
export { PDFNetworkStream };
|
||||
|
@ -14,21 +14,25 @@
|
||||
*/
|
||||
|
||||
import {
|
||||
assert, MissingPDFException, UnexpectedResponseException
|
||||
} from '../shared/util';
|
||||
import {
|
||||
getFilenameFromContentDispositionHeader
|
||||
} from './content_disposition';
|
||||
assert,
|
||||
MissingPDFException,
|
||||
UnexpectedResponseException,
|
||||
} from "../shared/util";
|
||||
import { getFilenameFromContentDispositionHeader } from "./content_disposition";
|
||||
|
||||
function validateRangeRequestCapabilities({ getResponseHeader, isHttp,
|
||||
rangeChunkSize, disableRange, }) {
|
||||
assert(rangeChunkSize > 0, 'Range chunk size must be larger than zero');
|
||||
function validateRangeRequestCapabilities({
|
||||
getResponseHeader,
|
||||
isHttp,
|
||||
rangeChunkSize,
|
||||
disableRange,
|
||||
}) {
|
||||
assert(rangeChunkSize > 0, "Range chunk size must be larger than zero");
|
||||
let returnValues = {
|
||||
allowRangeRequests: false,
|
||||
suggestedLength: undefined,
|
||||
};
|
||||
|
||||
let length = parseInt(getResponseHeader('Content-Length'), 10);
|
||||
let length = parseInt(getResponseHeader("Content-Length"), 10);
|
||||
if (!Number.isInteger(length)) {
|
||||
return returnValues;
|
||||
}
|
||||
@ -44,12 +48,12 @@ function validateRangeRequestCapabilities({ getResponseHeader, isHttp,
|
||||
if (disableRange || !isHttp) {
|
||||
return returnValues;
|
||||
}
|
||||
if (getResponseHeader('Accept-Ranges') !== 'bytes') {
|
||||
if (getResponseHeader("Accept-Ranges") !== "bytes") {
|
||||
return returnValues;
|
||||
}
|
||||
|
||||
let contentEncoding = getResponseHeader('Content-Encoding') || 'identity';
|
||||
if (contentEncoding !== 'identity') {
|
||||
let contentEncoding = getResponseHeader("Content-Encoding") || "identity";
|
||||
if (contentEncoding !== "identity") {
|
||||
return returnValues;
|
||||
}
|
||||
|
||||
@ -58,10 +62,10 @@ function validateRangeRequestCapabilities({ getResponseHeader, isHttp,
|
||||
}
|
||||
|
||||
function extractFilenameFromHeader(getResponseHeader) {
|
||||
const contentDisposition = getResponseHeader('Content-Disposition');
|
||||
const contentDisposition = getResponseHeader("Content-Disposition");
|
||||
if (contentDisposition) {
|
||||
let filename = getFilenameFromContentDispositionHeader(contentDisposition);
|
||||
if (filename.includes('%')) {
|
||||
if (filename.includes("%")) {
|
||||
try {
|
||||
filename = decodeURIComponent(filename);
|
||||
} catch (ex) {}
|
||||
@ -74,12 +78,17 @@ function extractFilenameFromHeader(getResponseHeader) {
|
||||
}
|
||||
|
||||
function createResponseStatusError(status, url) {
|
||||
if (status === 404 || status === 0 && /^file:/.test(url)) {
|
||||
if (status === 404 || (status === 0 && /^file:/.test(url))) {
|
||||
return new MissingPDFException('Missing PDF "' + url + '".');
|
||||
}
|
||||
return new UnexpectedResponseException(
|
||||
'Unexpected server response (' + status +
|
||||
') while retrieving PDF "' + url + '".', status);
|
||||
"Unexpected server response (" +
|
||||
status +
|
||||
') while retrieving PDF "' +
|
||||
url +
|
||||
'".',
|
||||
status
|
||||
);
|
||||
}
|
||||
|
||||
function validateResponseStatus(status) {
|
||||
|
@ -14,23 +14,27 @@
|
||||
*/
|
||||
/* globals __non_webpack_require__ */
|
||||
|
||||
let fs = __non_webpack_require__('fs');
|
||||
let http = __non_webpack_require__('http');
|
||||
let https = __non_webpack_require__('https');
|
||||
let url = __non_webpack_require__('url');
|
||||
let fs = __non_webpack_require__("fs");
|
||||
let http = __non_webpack_require__("http");
|
||||
let https = __non_webpack_require__("https");
|
||||
let url = __non_webpack_require__("url");
|
||||
|
||||
import {
|
||||
AbortException, assert, createPromiseCapability, MissingPDFException
|
||||
} from '../shared/util';
|
||||
AbortException,
|
||||
assert,
|
||||
createPromiseCapability,
|
||||
MissingPDFException,
|
||||
} from "../shared/util";
|
||||
import {
|
||||
extractFilenameFromHeader, validateRangeRequestCapabilities
|
||||
} from './network_utils';
|
||||
extractFilenameFromHeader,
|
||||
validateRangeRequestCapabilities,
|
||||
} from "./network_utils";
|
||||
|
||||
const fileUriRegex = /^file:\/\/\/[a-zA-Z]:\//;
|
||||
|
||||
function parseUrl(sourceUrl) {
|
||||
let parsedUrl = url.parse(sourceUrl);
|
||||
if (parsedUrl.protocol === 'file:' || parsedUrl.host) {
|
||||
if (parsedUrl.protocol === "file:" || parsedUrl.host) {
|
||||
return parsedUrl;
|
||||
}
|
||||
// Prepending 'file:///' to Windows absolute path.
|
||||
@ -39,7 +43,7 @@ function parseUrl(sourceUrl) {
|
||||
}
|
||||
// Changes protocol to 'file:' if url refers to filesystem.
|
||||
if (!parsedUrl.host) {
|
||||
parsedUrl.protocol = 'file:';
|
||||
parsedUrl.protocol = "file:";
|
||||
}
|
||||
return parsedUrl;
|
||||
}
|
||||
@ -48,10 +52,10 @@ class PDFNodeStream {
|
||||
constructor(source) {
|
||||
this.source = source;
|
||||
this.url = parseUrl(source.url);
|
||||
this.isHttp = this.url.protocol === 'http:' ||
|
||||
this.url.protocol === 'https:';
|
||||
this.isHttp =
|
||||
this.url.protocol === "http:" || this.url.protocol === "https:";
|
||||
// Check if url refers to filesystem.
|
||||
this.isFsUrl = this.url.protocol === 'file:';
|
||||
this.isFsUrl = this.url.protocol === "file:";
|
||||
this.httpHeaders = (this.isHttp && source.httpHeaders) || {};
|
||||
|
||||
this._fullRequestReader = null;
|
||||
@ -59,14 +63,14 @@ class PDFNodeStream {
|
||||
}
|
||||
|
||||
get _progressiveDataLength() {
|
||||
return (this._fullRequestReader ? this._fullRequestReader._loaded : 0);
|
||||
return this._fullRequestReader ? this._fullRequestReader._loaded : 0;
|
||||
}
|
||||
|
||||
getFullReader() {
|
||||
assert(!this._fullRequestReader);
|
||||
this._fullRequestReader = this.isFsUrl ?
|
||||
new PDFNodeStreamFsFullReader(this) :
|
||||
new PDFNodeStreamFullReader(this);
|
||||
this._fullRequestReader = this.isFsUrl
|
||||
? new PDFNodeStreamFsFullReader(this)
|
||||
: new PDFNodeStreamFullReader(this);
|
||||
return this._fullRequestReader;
|
||||
}
|
||||
|
||||
@ -74,9 +78,9 @@ class PDFNodeStream {
|
||||
if (end <= this._progressiveDataLength) {
|
||||
return null;
|
||||
}
|
||||
let rangeReader = this.isFsUrl ?
|
||||
new PDFNodeStreamFsRangeReader(this, start, end) :
|
||||
new PDFNodeStreamRangeReader(this, start, end);
|
||||
let rangeReader = this.isFsUrl
|
||||
? new PDFNodeStreamFsRangeReader(this, start, end)
|
||||
: new PDFNodeStreamRangeReader(this, start, end);
|
||||
this._rangeRequestReaders.push(rangeReader);
|
||||
return rangeReader;
|
||||
}
|
||||
@ -141,7 +145,7 @@ class BaseFullReader {
|
||||
async read() {
|
||||
await this._readCapability.promise;
|
||||
if (this._done) {
|
||||
return { value: undefined, done: true, };
|
||||
return { value: undefined, done: true };
|
||||
}
|
||||
if (this._storedError) {
|
||||
throw this._storedError;
|
||||
@ -161,7 +165,7 @@ class BaseFullReader {
|
||||
}
|
||||
// Ensure that `read()` method returns ArrayBuffer.
|
||||
let buffer = new Uint8Array(chunk).buffer;
|
||||
return { value: buffer, done: false, };
|
||||
return { value: buffer, done: false };
|
||||
}
|
||||
|
||||
cancel(reason) {
|
||||
@ -181,25 +185,25 @@ class BaseFullReader {
|
||||
|
||||
_setReadableStream(readableStream) {
|
||||
this._readableStream = readableStream;
|
||||
readableStream.on('readable', () => {
|
||||
readableStream.on("readable", () => {
|
||||
this._readCapability.resolve();
|
||||
});
|
||||
|
||||
readableStream.on('end', () => {
|
||||
readableStream.on("end", () => {
|
||||
// Destroy readable to minimize resource usage.
|
||||
readableStream.destroy();
|
||||
this._done = true;
|
||||
this._readCapability.resolve();
|
||||
});
|
||||
|
||||
readableStream.on('error', (reason) => {
|
||||
readableStream.on("error", reason => {
|
||||
this._error(reason);
|
||||
});
|
||||
|
||||
// We need to stop reading when range is supported and streaming is
|
||||
// disabled.
|
||||
if (!this._isStreamingSupported && this._isRangeSupported) {
|
||||
this._error(new AbortException('streaming is disabled'));
|
||||
this._error(new AbortException("streaming is disabled"));
|
||||
}
|
||||
|
||||
// Destroy ReadableStream if already in errored state.
|
||||
@ -229,7 +233,7 @@ class BaseRangeReader {
|
||||
async read() {
|
||||
await this._readCapability.promise;
|
||||
if (this._done) {
|
||||
return { value: undefined, done: true, };
|
||||
return { value: undefined, done: true };
|
||||
}
|
||||
if (this._storedError) {
|
||||
throw this._storedError;
|
||||
@ -242,11 +246,11 @@ class BaseRangeReader {
|
||||
}
|
||||
this._loaded += chunk.length;
|
||||
if (this.onProgress) {
|
||||
this.onProgress({ loaded: this._loaded, });
|
||||
this.onProgress({ loaded: this._loaded });
|
||||
}
|
||||
// Ensure that `read()` method returns ArrayBuffer.
|
||||
let buffer = new Uint8Array(chunk).buffer;
|
||||
return { value: buffer, done: false, };
|
||||
return { value: buffer, done: false };
|
||||
}
|
||||
|
||||
cancel(reason) {
|
||||
@ -266,18 +270,18 @@ class BaseRangeReader {
|
||||
|
||||
_setReadableStream(readableStream) {
|
||||
this._readableStream = readableStream;
|
||||
readableStream.on('readable', () => {
|
||||
readableStream.on("readable", () => {
|
||||
this._readCapability.resolve();
|
||||
});
|
||||
|
||||
readableStream.on('end', () => {
|
||||
readableStream.on("end", () => {
|
||||
// Destroy readableStream to minimize resource usage.
|
||||
readableStream.destroy();
|
||||
this._done = true;
|
||||
this._readCapability.resolve();
|
||||
});
|
||||
|
||||
readableStream.on('error', (reason) => {
|
||||
readableStream.on("error", reason => {
|
||||
this._error(reason);
|
||||
});
|
||||
|
||||
@ -295,7 +299,7 @@ function createRequestOptions(url, headers) {
|
||||
host: url.hostname,
|
||||
port: url.port,
|
||||
path: url.path,
|
||||
method: 'GET',
|
||||
method: "GET",
|
||||
headers,
|
||||
};
|
||||
}
|
||||
@ -304,7 +308,7 @@ class PDFNodeStreamFullReader extends BaseFullReader {
|
||||
constructor(stream) {
|
||||
super(stream);
|
||||
|
||||
let handleResponse = (response) => {
|
||||
let handleResponse = response => {
|
||||
if (response.statusCode === 404) {
|
||||
const error = new MissingPDFException(`Missing PDF "${this._url}".`);
|
||||
this._storedError = error;
|
||||
@ -314,18 +318,20 @@ class PDFNodeStreamFullReader extends BaseFullReader {
|
||||
this._headersCapability.resolve();
|
||||
this._setReadableStream(response);
|
||||
|
||||
const getResponseHeader = (name) => {
|
||||
const getResponseHeader = name => {
|
||||
// Make sure that headers name are in lower case, as mentioned
|
||||
// here: https://nodejs.org/api/http.html#http_message_headers.
|
||||
return this._readableStream.headers[name.toLowerCase()];
|
||||
};
|
||||
let { allowRangeRequests, suggestedLength, } =
|
||||
validateRangeRequestCapabilities({
|
||||
getResponseHeader,
|
||||
isHttp: stream.isHttp,
|
||||
rangeChunkSize: this._rangeChunkSize,
|
||||
disableRange: this._disableRange,
|
||||
});
|
||||
let {
|
||||
allowRangeRequests,
|
||||
suggestedLength,
|
||||
} = validateRangeRequestCapabilities({
|
||||
getResponseHeader,
|
||||
isHttp: stream.isHttp,
|
||||
rangeChunkSize: this._rangeChunkSize,
|
||||
disableRange: this._disableRange,
|
||||
});
|
||||
|
||||
this._isRangeSupported = allowRangeRequests;
|
||||
// Setting right content length.
|
||||
@ -335,17 +341,19 @@ class PDFNodeStreamFullReader extends BaseFullReader {
|
||||
};
|
||||
|
||||
this._request = null;
|
||||
if (this._url.protocol === 'http:') {
|
||||
if (this._url.protocol === "http:") {
|
||||
this._request = http.request(
|
||||
createRequestOptions(this._url, stream.httpHeaders),
|
||||
handleResponse);
|
||||
handleResponse
|
||||
);
|
||||
} else {
|
||||
this._request = https.request(
|
||||
createRequestOptions(this._url, stream.httpHeaders),
|
||||
handleResponse);
|
||||
handleResponse
|
||||
);
|
||||
}
|
||||
|
||||
this._request.on('error', (reason) => {
|
||||
this._request.on("error", reason => {
|
||||
this._storedError = reason;
|
||||
this._headersCapability.reject(reason);
|
||||
});
|
||||
@ -363,14 +371,14 @@ class PDFNodeStreamRangeReader extends BaseRangeReader {
|
||||
this._httpHeaders = {};
|
||||
for (let property in stream.httpHeaders) {
|
||||
let value = stream.httpHeaders[property];
|
||||
if (typeof value === 'undefined') {
|
||||
if (typeof value === "undefined") {
|
||||
continue;
|
||||
}
|
||||
this._httpHeaders[property] = value;
|
||||
}
|
||||
this._httpHeaders['Range'] = `bytes=${start}-${end - 1}`;
|
||||
this._httpHeaders["Range"] = `bytes=${start}-${end - 1}`;
|
||||
|
||||
let handleResponse = (response) => {
|
||||
let handleResponse = response => {
|
||||
if (response.statusCode === 404) {
|
||||
const error = new MissingPDFException(`Missing PDF "${this._url}".`);
|
||||
this._storedError = error;
|
||||
@ -380,17 +388,19 @@ class PDFNodeStreamRangeReader extends BaseRangeReader {
|
||||
};
|
||||
|
||||
this._request = null;
|
||||
if (this._url.protocol === 'http:') {
|
||||
if (this._url.protocol === "http:") {
|
||||
this._request = http.request(
|
||||
createRequestOptions(this._url, this._httpHeaders),
|
||||
handleResponse);
|
||||
handleResponse
|
||||
);
|
||||
} else {
|
||||
this._request = https.request(
|
||||
createRequestOptions(this._url, this._httpHeaders),
|
||||
handleResponse);
|
||||
handleResponse
|
||||
);
|
||||
}
|
||||
|
||||
this._request.on('error', (reason) => {
|
||||
this._request.on("error", reason => {
|
||||
this._storedError = reason;
|
||||
});
|
||||
this._request.end();
|
||||
@ -405,12 +415,12 @@ class PDFNodeStreamFsFullReader extends BaseFullReader {
|
||||
|
||||
// Remove the extra slash to get right path from url like `file:///C:/`
|
||||
if (fileUriRegex.test(this._url.href)) {
|
||||
path = path.replace(/^\//, '');
|
||||
path = path.replace(/^\//, "");
|
||||
}
|
||||
|
||||
fs.lstat(path, (error, stat) => {
|
||||
if (error) {
|
||||
if (error.code === 'ENOENT') {
|
||||
if (error.code === "ENOENT") {
|
||||
error = new MissingPDFException(`Missing PDF "${path}".`);
|
||||
}
|
||||
this._storedError = error;
|
||||
@ -434,14 +444,11 @@ class PDFNodeStreamFsRangeReader extends BaseRangeReader {
|
||||
|
||||
// Remove the extra slash to get right path from url like `file:///C:/`
|
||||
if (fileUriRegex.test(this._url.href)) {
|
||||
path = path.replace(/^\//, '');
|
||||
path = path.replace(/^\//, "");
|
||||
}
|
||||
|
||||
this._setReadableStream(
|
||||
fs.createReadStream(path, { start, end: end - 1, }));
|
||||
this._setReadableStream(fs.createReadStream(path, { start, end: end - 1 }));
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
PDFNodeStream,
|
||||
};
|
||||
export { PDFNodeStream };
|
||||
|
@ -13,12 +13,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { FormatError, info, Util } from '../shared/util';
|
||||
import { FormatError, info, Util } from "../shared/util";
|
||||
|
||||
var ShadingIRs = {};
|
||||
|
||||
function applyBoundingBox(ctx, bbox) {
|
||||
if (!bbox || typeof Path2D === 'undefined') {
|
||||
if (!bbox || typeof Path2D === "undefined") {
|
||||
return;
|
||||
}
|
||||
const width = bbox[2] - bbox[0];
|
||||
@ -38,13 +38,13 @@ ShadingIRs.RadialAxial = {
|
||||
var r0 = raw[6];
|
||||
var r1 = raw[7];
|
||||
return {
|
||||
type: 'Pattern',
|
||||
type: "Pattern",
|
||||
getPattern: function RadialAxial_getPattern(ctx) {
|
||||
applyBoundingBox(ctx, bbox);
|
||||
var grad;
|
||||
if (type === 'axial') {
|
||||
if (type === "axial") {
|
||||
grad = ctx.createLinearGradient(p0[0], p0[1], p1[0], p1[1]);
|
||||
} else if (type === 'radial') {
|
||||
} else if (type === "radial") {
|
||||
grad = ctx.createRadialGradient(p0[0], p0[1], r0, p1[0], p1[1], r1);
|
||||
}
|
||||
|
||||
@ -61,17 +61,34 @@ ShadingIRs.RadialAxial = {
|
||||
var createMeshCanvas = (function createMeshCanvasClosure() {
|
||||
function drawTriangle(data, context, p1, p2, p3, c1, c2, c3) {
|
||||
// Very basic Gouraud-shaded triangle rasterization algorithm.
|
||||
var coords = context.coords, colors = context.colors;
|
||||
var bytes = data.data, rowSize = data.width * 4;
|
||||
var coords = context.coords,
|
||||
colors = context.colors;
|
||||
var bytes = data.data,
|
||||
rowSize = data.width * 4;
|
||||
var tmp;
|
||||
if (coords[p1 + 1] > coords[p2 + 1]) {
|
||||
tmp = p1; p1 = p2; p2 = tmp; tmp = c1; c1 = c2; c2 = tmp;
|
||||
tmp = p1;
|
||||
p1 = p2;
|
||||
p2 = tmp;
|
||||
tmp = c1;
|
||||
c1 = c2;
|
||||
c2 = tmp;
|
||||
}
|
||||
if (coords[p2 + 1] > coords[p3 + 1]) {
|
||||
tmp = p2; p2 = p3; p3 = tmp; tmp = c2; c2 = c3; c3 = tmp;
|
||||
tmp = p2;
|
||||
p2 = p3;
|
||||
p3 = tmp;
|
||||
tmp = c2;
|
||||
c2 = c3;
|
||||
c3 = tmp;
|
||||
}
|
||||
if (coords[p1 + 1] > coords[p2 + 1]) {
|
||||
tmp = p1; p1 = p2; p2 = tmp; tmp = c1; c1 = c2; c2 = tmp;
|
||||
tmp = p1;
|
||||
p1 = p2;
|
||||
p2 = tmp;
|
||||
tmp = c1;
|
||||
c1 = c2;
|
||||
c2 = tmp;
|
||||
}
|
||||
var x1 = (coords[p1] + context.offsetX) * context.scaleX;
|
||||
var y1 = (coords[p1 + 1] + context.offsetY) * context.scaleY;
|
||||
@ -82,11 +99,18 @@ var createMeshCanvas = (function createMeshCanvasClosure() {
|
||||
if (y1 >= y3) {
|
||||
return;
|
||||
}
|
||||
var c1r = colors[c1], c1g = colors[c1 + 1], c1b = colors[c1 + 2];
|
||||
var c2r = colors[c2], c2g = colors[c2 + 1], c2b = colors[c2 + 2];
|
||||
var c3r = colors[c3], c3g = colors[c3 + 1], c3b = colors[c3 + 2];
|
||||
var c1r = colors[c1],
|
||||
c1g = colors[c1 + 1],
|
||||
c1b = colors[c1 + 2];
|
||||
var c2r = colors[c2],
|
||||
c2g = colors[c2 + 1],
|
||||
c2b = colors[c2 + 2];
|
||||
var c3r = colors[c3],
|
||||
c3g = colors[c3 + 1],
|
||||
c3b = colors[c3 + 2];
|
||||
|
||||
var minY = Math.round(y1), maxY = Math.round(y3);
|
||||
var minY = Math.round(y1),
|
||||
maxY = Math.round(y3);
|
||||
var xa, car, cag, cab;
|
||||
var xb, cbr, cbg, cbb;
|
||||
var k;
|
||||
@ -128,36 +152,65 @@ var createMeshCanvas = (function createMeshCanvasClosure() {
|
||||
var cs = figure.colors;
|
||||
var i, ii;
|
||||
switch (figure.type) {
|
||||
case 'lattice':
|
||||
case "lattice":
|
||||
var verticesPerRow = figure.verticesPerRow;
|
||||
var rows = Math.floor(ps.length / verticesPerRow) - 1;
|
||||
var cols = verticesPerRow - 1;
|
||||
for (i = 0; i < rows; i++) {
|
||||
var q = i * verticesPerRow;
|
||||
for (var j = 0; j < cols; j++, q++) {
|
||||
drawTriangle(data, context,
|
||||
ps[q], ps[q + 1], ps[q + verticesPerRow],
|
||||
cs[q], cs[q + 1], cs[q + verticesPerRow]);
|
||||
drawTriangle(data, context,
|
||||
ps[q + verticesPerRow + 1], ps[q + 1], ps[q + verticesPerRow],
|
||||
cs[q + verticesPerRow + 1], cs[q + 1], cs[q + verticesPerRow]);
|
||||
drawTriangle(
|
||||
data,
|
||||
context,
|
||||
ps[q],
|
||||
ps[q + 1],
|
||||
ps[q + verticesPerRow],
|
||||
cs[q],
|
||||
cs[q + 1],
|
||||
cs[q + verticesPerRow]
|
||||
);
|
||||
drawTriangle(
|
||||
data,
|
||||
context,
|
||||
ps[q + verticesPerRow + 1],
|
||||
ps[q + 1],
|
||||
ps[q + verticesPerRow],
|
||||
cs[q + verticesPerRow + 1],
|
||||
cs[q + 1],
|
||||
cs[q + verticesPerRow]
|
||||
);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'triangles':
|
||||
case "triangles":
|
||||
for (i = 0, ii = ps.length; i < ii; i += 3) {
|
||||
drawTriangle(data, context,
|
||||
ps[i], ps[i + 1], ps[i + 2],
|
||||
cs[i], cs[i + 1], cs[i + 2]);
|
||||
drawTriangle(
|
||||
data,
|
||||
context,
|
||||
ps[i],
|
||||
ps[i + 1],
|
||||
ps[i + 2],
|
||||
cs[i],
|
||||
cs[i + 1],
|
||||
cs[i + 2]
|
||||
);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new Error('illegal figure');
|
||||
throw new Error("illegal figure");
|
||||
}
|
||||
}
|
||||
|
||||
function createMeshCanvas(bounds, combinesScale, coords, colors, figures,
|
||||
backgroundColor, cachedCanvases, webGLContext) {
|
||||
function createMeshCanvas(
|
||||
bounds,
|
||||
combinesScale,
|
||||
coords,
|
||||
colors,
|
||||
figures,
|
||||
backgroundColor,
|
||||
cachedCanvases,
|
||||
webGLContext
|
||||
) {
|
||||
// we will increase scale on some weird factor to let antialiasing take
|
||||
// care of "rough" edges
|
||||
var EXPECTED_SCALE = 1.1;
|
||||
@ -172,10 +225,14 @@ var createMeshCanvas = (function createMeshCanvasClosure() {
|
||||
var boundsWidth = Math.ceil(bounds[2]) - offsetX;
|
||||
var boundsHeight = Math.ceil(bounds[3]) - offsetY;
|
||||
|
||||
var width = Math.min(Math.ceil(Math.abs(boundsWidth * combinesScale[0] *
|
||||
EXPECTED_SCALE)), MAX_PATTERN_SIZE);
|
||||
var height = Math.min(Math.ceil(Math.abs(boundsHeight * combinesScale[1] *
|
||||
EXPECTED_SCALE)), MAX_PATTERN_SIZE);
|
||||
var width = Math.min(
|
||||
Math.ceil(Math.abs(boundsWidth * combinesScale[0] * EXPECTED_SCALE)),
|
||||
MAX_PATTERN_SIZE
|
||||
);
|
||||
var height = Math.min(
|
||||
Math.ceil(Math.abs(boundsHeight * combinesScale[1] * EXPECTED_SCALE)),
|
||||
MAX_PATTERN_SIZE
|
||||
);
|
||||
var scaleX = boundsWidth / width;
|
||||
var scaleY = boundsHeight / height;
|
||||
|
||||
@ -201,13 +258,21 @@ var createMeshCanvas = (function createMeshCanvasClosure() {
|
||||
context,
|
||||
});
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=972126
|
||||
tmpCanvas = cachedCanvases.getCanvas('mesh', paddedWidth, paddedHeight,
|
||||
false);
|
||||
tmpCanvas = cachedCanvases.getCanvas(
|
||||
"mesh",
|
||||
paddedWidth,
|
||||
paddedHeight,
|
||||
false
|
||||
);
|
||||
tmpCanvas.context.drawImage(canvas, BORDER_SIZE, BORDER_SIZE);
|
||||
canvas = tmpCanvas.canvas;
|
||||
} else {
|
||||
tmpCanvas = cachedCanvases.getCanvas('mesh', paddedWidth, paddedHeight,
|
||||
false);
|
||||
tmpCanvas = cachedCanvases.getCanvas(
|
||||
"mesh",
|
||||
paddedWidth,
|
||||
paddedHeight,
|
||||
false
|
||||
);
|
||||
var tmpCtx = tmpCanvas.context;
|
||||
|
||||
var data = tmpCtx.createImageData(width, height);
|
||||
@ -249,7 +314,7 @@ ShadingIRs.Mesh = {
|
||||
var bbox = raw[7];
|
||||
var background = raw[8];
|
||||
return {
|
||||
type: 'Pattern',
|
||||
type: "Pattern",
|
||||
getPattern: function Mesh_getPattern(ctx, owner, shadingFill) {
|
||||
applyBoundingBox(ctx, bbox);
|
||||
var scale;
|
||||
@ -260,16 +325,22 @@ ShadingIRs.Mesh = {
|
||||
scale = Util.singularValueDecompose2dScale(owner.baseTransform);
|
||||
if (matrix) {
|
||||
var matrixScale = Util.singularValueDecompose2dScale(matrix);
|
||||
scale = [scale[0] * matrixScale[0],
|
||||
scale[1] * matrixScale[1]];
|
||||
scale = [scale[0] * matrixScale[0], scale[1] * matrixScale[1]];
|
||||
}
|
||||
}
|
||||
|
||||
// Rasterizing on the main thread since sending/queue large canvases
|
||||
// might cause OOM.
|
||||
var temporaryPatternCanvas = createMeshCanvas(bounds, scale, coords,
|
||||
colors, figures, shadingFill ? null : background,
|
||||
owner.cachedCanvases, owner.webGLContext);
|
||||
var temporaryPatternCanvas = createMeshCanvas(
|
||||
bounds,
|
||||
scale,
|
||||
coords,
|
||||
colors,
|
||||
figures,
|
||||
shadingFill ? null : background,
|
||||
owner.cachedCanvases,
|
||||
owner.webGLContext
|
||||
);
|
||||
|
||||
if (!shadingFill) {
|
||||
ctx.setTransform.apply(ctx, owner.baseTransform);
|
||||
@ -278,12 +349,13 @@ ShadingIRs.Mesh = {
|
||||
}
|
||||
}
|
||||
|
||||
ctx.translate(temporaryPatternCanvas.offsetX,
|
||||
temporaryPatternCanvas.offsetY);
|
||||
ctx.scale(temporaryPatternCanvas.scaleX,
|
||||
temporaryPatternCanvas.scaleY);
|
||||
ctx.translate(
|
||||
temporaryPatternCanvas.offsetX,
|
||||
temporaryPatternCanvas.offsetY
|
||||
);
|
||||
ctx.scale(temporaryPatternCanvas.scaleX, temporaryPatternCanvas.scaleY);
|
||||
|
||||
return ctx.createPattern(temporaryPatternCanvas.canvas, 'no-repeat');
|
||||
return ctx.createPattern(temporaryPatternCanvas.canvas, "no-repeat");
|
||||
},
|
||||
};
|
||||
},
|
||||
@ -292,9 +364,9 @@ ShadingIRs.Mesh = {
|
||||
ShadingIRs.Dummy = {
|
||||
fromIR: function Dummy_fromIR() {
|
||||
return {
|
||||
type: 'Pattern',
|
||||
type: "Pattern",
|
||||
getPattern: function Dummy_fromIR_getPattern() {
|
||||
return 'hotpink';
|
||||
return "hotpink";
|
||||
},
|
||||
};
|
||||
},
|
||||
@ -327,7 +399,7 @@ var TilingPattern = (function TilingPatternClosure() {
|
||||
this.color = color;
|
||||
this.canvasGraphicsFactory = canvasGraphicsFactory;
|
||||
this.baseTransform = baseTransform;
|
||||
this.type = 'Pattern';
|
||||
this.type = "Pattern";
|
||||
this.ctx = ctx;
|
||||
}
|
||||
|
||||
@ -342,7 +414,7 @@ var TilingPattern = (function TilingPatternClosure() {
|
||||
var color = this.color;
|
||||
var canvasGraphicsFactory = this.canvasGraphicsFactory;
|
||||
|
||||
info('TilingType: ' + tilingType);
|
||||
info("TilingType: " + tilingType);
|
||||
|
||||
// A tiling pattern as defined by PDF spec 8.7.2 is a cell whose size is
|
||||
// described by bbox, and may repeat regularly by shifting the cell by
|
||||
@ -364,25 +436,41 @@ var TilingPattern = (function TilingPatternClosure() {
|
||||
// TODO: Fix the implementation, to allow this scenario to be painted
|
||||
// correctly.
|
||||
|
||||
var x0 = bbox[0], y0 = bbox[1], x1 = bbox[2], y1 = bbox[3];
|
||||
var x0 = bbox[0],
|
||||
y0 = bbox[1],
|
||||
x1 = bbox[2],
|
||||
y1 = bbox[3];
|
||||
|
||||
// Obtain scale from matrix and current transformation matrix.
|
||||
var matrixScale = Util.singularValueDecompose2dScale(this.matrix);
|
||||
var curMatrixScale = Util.singularValueDecompose2dScale(
|
||||
this.baseTransform);
|
||||
var combinedScale = [matrixScale[0] * curMatrixScale[0],
|
||||
matrixScale[1] * curMatrixScale[1]];
|
||||
this.baseTransform
|
||||
);
|
||||
var combinedScale = [
|
||||
matrixScale[0] * curMatrixScale[0],
|
||||
matrixScale[1] * curMatrixScale[1],
|
||||
];
|
||||
|
||||
// Use width and height values that are as close as possible to the end
|
||||
// result when the pattern is used. Too low value makes the pattern look
|
||||
// blurry. Too large value makes it look too crispy.
|
||||
var dimx = this.getSizeAndScale(xstep, this.ctx.canvas.width,
|
||||
combinedScale[0]);
|
||||
var dimy = this.getSizeAndScale(ystep, this.ctx.canvas.height,
|
||||
combinedScale[1]);
|
||||
var dimx = this.getSizeAndScale(
|
||||
xstep,
|
||||
this.ctx.canvas.width,
|
||||
combinedScale[0]
|
||||
);
|
||||
var dimy = this.getSizeAndScale(
|
||||
ystep,
|
||||
this.ctx.canvas.height,
|
||||
combinedScale[1]
|
||||
);
|
||||
|
||||
var tmpCanvas = owner.cachedCanvases.getCanvas('pattern',
|
||||
dimx.size, dimy.size, true);
|
||||
var tmpCanvas = owner.cachedCanvases.getCanvas(
|
||||
"pattern",
|
||||
dimx.size,
|
||||
dimy.size,
|
||||
true
|
||||
);
|
||||
var tmpCtx = tmpCanvas.context;
|
||||
var graphics = canvasGraphicsFactory.createCanvasGraphics(tmpCtx);
|
||||
graphics.groupLevel = owner.groupLevel;
|
||||
@ -406,8 +494,11 @@ var TilingPattern = (function TilingPatternClosure() {
|
||||
return tmpCanvas.canvas;
|
||||
},
|
||||
|
||||
getSizeAndScale:
|
||||
function TilingPattern_getSizeAndScale(step, realOutputSize, scale) {
|
||||
getSizeAndScale: function TilingPattern_getSizeAndScale(
|
||||
step,
|
||||
realOutputSize,
|
||||
scale
|
||||
) {
|
||||
// xstep / ystep may be negative -- normalize.
|
||||
step = Math.abs(step);
|
||||
// MAX_PATTERN_SIZE is used to avoid OOM situation.
|
||||
@ -421,7 +512,7 @@ var TilingPattern = (function TilingPatternClosure() {
|
||||
} else {
|
||||
scale = size / step;
|
||||
}
|
||||
return { scale, size, };
|
||||
return { scale, size };
|
||||
},
|
||||
|
||||
clipBbox: function clipBbox(graphics, bbox, x0, y0, x1, y1) {
|
||||
@ -434,29 +525,33 @@ var TilingPattern = (function TilingPatternClosure() {
|
||||
}
|
||||
},
|
||||
|
||||
setFillAndStrokeStyleToContext:
|
||||
function setFillAndStrokeStyleToContext(graphics, paintType, color) {
|
||||
let context = graphics.ctx, current = graphics.current;
|
||||
switch (paintType) {
|
||||
case PaintType.COLORED:
|
||||
var ctx = this.ctx;
|
||||
context.fillStyle = ctx.fillStyle;
|
||||
context.strokeStyle = ctx.strokeStyle;
|
||||
current.fillColor = ctx.fillStyle;
|
||||
current.strokeColor = ctx.strokeStyle;
|
||||
break;
|
||||
case PaintType.UNCOLORED:
|
||||
var cssColor = Util.makeCssRgb(color[0], color[1], color[2]);
|
||||
context.fillStyle = cssColor;
|
||||
context.strokeStyle = cssColor;
|
||||
// Set color needed by image masks (fixes issues 3226 and 8741).
|
||||
current.fillColor = cssColor;
|
||||
current.strokeColor = cssColor;
|
||||
break;
|
||||
default:
|
||||
throw new FormatError(`Unsupported paint type: ${paintType}`);
|
||||
}
|
||||
},
|
||||
setFillAndStrokeStyleToContext: function setFillAndStrokeStyleToContext(
|
||||
graphics,
|
||||
paintType,
|
||||
color
|
||||
) {
|
||||
let context = graphics.ctx,
|
||||
current = graphics.current;
|
||||
switch (paintType) {
|
||||
case PaintType.COLORED:
|
||||
var ctx = this.ctx;
|
||||
context.fillStyle = ctx.fillStyle;
|
||||
context.strokeStyle = ctx.strokeStyle;
|
||||
current.fillColor = ctx.fillStyle;
|
||||
current.strokeColor = ctx.strokeStyle;
|
||||
break;
|
||||
case PaintType.UNCOLORED:
|
||||
var cssColor = Util.makeCssRgb(color[0], color[1], color[2]);
|
||||
context.fillStyle = cssColor;
|
||||
context.strokeStyle = cssColor;
|
||||
// Set color needed by image masks (fixes issues 3226 and 8741).
|
||||
current.fillColor = cssColor;
|
||||
current.strokeColor = cssColor;
|
||||
break;
|
||||
default:
|
||||
throw new FormatError(`Unsupported paint type: ${paintType}`);
|
||||
}
|
||||
},
|
||||
|
||||
getPattern: function TilingPattern_getPattern(ctx, owner) {
|
||||
ctx = this.ctx;
|
||||
@ -466,14 +561,11 @@ var TilingPattern = (function TilingPatternClosure() {
|
||||
|
||||
var temporaryPatternCanvas = this.createPatternCanvas(owner);
|
||||
|
||||
return ctx.createPattern(temporaryPatternCanvas, 'repeat');
|
||||
return ctx.createPattern(temporaryPatternCanvas, "repeat");
|
||||
},
|
||||
};
|
||||
|
||||
return TilingPattern;
|
||||
})();
|
||||
|
||||
export {
|
||||
getShadingPatternFromIR,
|
||||
TilingPattern,
|
||||
};
|
||||
export { getShadingPatternFromIR, TilingPattern };
|
||||
|
2978
src/display/svg.js
2978
src/display/svg.js
File diff suppressed because it is too large
Load Diff
@ -13,7 +13,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { AbortException, createPromiseCapability, Util } from '../shared/util';
|
||||
import { AbortException, createPromiseCapability, Util } from "../shared/util";
|
||||
|
||||
/**
|
||||
* Text layer render parameters.
|
||||
@ -48,7 +48,7 @@ var renderTextLayer = (function renderTextLayerClosure() {
|
||||
|
||||
function appendText(task, geom, styles) {
|
||||
// Initialize all used properties to keep the caches monomorphic.
|
||||
var textDiv = document.createElement('span');
|
||||
var textDiv = document.createElement("span");
|
||||
var textDivProperties = {
|
||||
angle: 0,
|
||||
canvasWidth: 0,
|
||||
@ -74,7 +74,7 @@ var renderTextLayer = (function renderTextLayerClosure() {
|
||||
if (style.vertical) {
|
||||
angle += Math.PI / 2;
|
||||
}
|
||||
var fontHeight = Math.sqrt((tx[2] * tx[2]) + (tx[3] * tx[3]));
|
||||
var fontHeight = Math.sqrt(tx[2] * tx[2] + tx[3] * tx[3]);
|
||||
var fontAscent = fontHeight;
|
||||
if (style.ascent) {
|
||||
fontAscent = style.ascent * fontAscent;
|
||||
@ -87,8 +87,8 @@ var renderTextLayer = (function renderTextLayerClosure() {
|
||||
left = tx[4];
|
||||
top = tx[5] - fontAscent;
|
||||
} else {
|
||||
left = tx[4] + (fontAscent * Math.sin(angle));
|
||||
top = tx[5] - (fontAscent * Math.cos(angle));
|
||||
left = tx[4] + fontAscent * Math.sin(angle);
|
||||
top = tx[5] - fontAscent * Math.cos(angle);
|
||||
}
|
||||
// Setting the style properties individually, rather than all at once,
|
||||
// should be OK since the `textDiv` isn't appended to the document yet.
|
||||
@ -122,13 +122,14 @@ var renderTextLayer = (function renderTextLayerClosure() {
|
||||
}
|
||||
|
||||
if (task._enhanceTextSelection) {
|
||||
var angleCos = 1, angleSin = 0;
|
||||
var angleCos = 1,
|
||||
angleSin = 0;
|
||||
if (angle !== 0) {
|
||||
angleCos = Math.cos(angle);
|
||||
angleSin = Math.sin(angle);
|
||||
}
|
||||
var divWidth = (style.vertical ? geom.height : geom.width) *
|
||||
task._viewport.scale;
|
||||
var divWidth =
|
||||
(style.vertical ? geom.height : geom.width) * task._viewport.scale;
|
||||
var divHeight = fontHeight;
|
||||
|
||||
var m, b;
|
||||
@ -195,12 +196,15 @@ var renderTextLayer = (function renderTextLayerClosure() {
|
||||
}
|
||||
// Box is rotated -- trying to find padding so rotated div will not
|
||||
// exceed its expanded bounds.
|
||||
var e = expanded[i], b = bounds[i];
|
||||
var m = b.m, c = m[0], s = m[1];
|
||||
var e = expanded[i],
|
||||
b = bounds[i];
|
||||
var m = b.m,
|
||||
c = m[0],
|
||||
s = m[1];
|
||||
// Finding intersections with expanded box.
|
||||
var points = [[0, 0], [0, b.size[1]], [b.size[0], 0], b.size];
|
||||
var ts = new Float64Array(64);
|
||||
points.forEach(function (p, i) {
|
||||
points.forEach(function(p, i) {
|
||||
var t = Util.applyTransform(p, m);
|
||||
ts[i + 0] = c && (e.left - t[0]) / c;
|
||||
ts[i + 4] = s && (e.top - t[1]) / s;
|
||||
@ -222,7 +226,7 @@ var renderTextLayer = (function renderTextLayerClosure() {
|
||||
ts[i + 56] = s && (e.right - t[0]) / s;
|
||||
ts[i + 60] = c && (e.bottom - t[1]) / -c;
|
||||
});
|
||||
var findPositiveMin = function (ts, offset, count) {
|
||||
var findPositiveMin = function(ts, offset, count) {
|
||||
var result = 0;
|
||||
for (var i = 0; i < count; i++) {
|
||||
var t = ts[offset++];
|
||||
@ -244,7 +248,7 @@ var renderTextLayer = (function renderTextLayerClosure() {
|
||||
}
|
||||
|
||||
function expandBounds(width, height, boxes) {
|
||||
var bounds = boxes.map(function (box, i) {
|
||||
var bounds = boxes.map(function(box, i) {
|
||||
return {
|
||||
x1: box.left,
|
||||
y1: box.top,
|
||||
@ -257,7 +261,7 @@ var renderTextLayer = (function renderTextLayerClosure() {
|
||||
});
|
||||
expandBoundsLTR(width, bounds);
|
||||
var expanded = new Array(boxes.length);
|
||||
bounds.forEach(function (b) {
|
||||
bounds.forEach(function(b) {
|
||||
var i = b.index;
|
||||
expanded[i] = {
|
||||
left: b.x1New,
|
||||
@ -269,8 +273,9 @@ var renderTextLayer = (function renderTextLayerClosure() {
|
||||
|
||||
// Rotating on 90 degrees and extending extended boxes. Reusing the bounds
|
||||
// array and objects.
|
||||
boxes.map(function (box, i) {
|
||||
var e = expanded[i], b = bounds[i];
|
||||
boxes.map(function(box, i) {
|
||||
var e = expanded[i],
|
||||
b = bounds[i];
|
||||
b.x1 = box.top;
|
||||
b.y1 = width - e.right;
|
||||
b.x2 = box.bottom;
|
||||
@ -281,7 +286,7 @@ var renderTextLayer = (function renderTextLayerClosure() {
|
||||
});
|
||||
expandBoundsLTR(height, bounds);
|
||||
|
||||
bounds.forEach(function (b) {
|
||||
bounds.forEach(function(b) {
|
||||
var i = b.index;
|
||||
expanded[i].top = b.x1New;
|
||||
expanded[i].bottom = b.x2New;
|
||||
@ -291,7 +296,7 @@ var renderTextLayer = (function renderTextLayerClosure() {
|
||||
|
||||
function expandBoundsLTR(width, bounds) {
|
||||
// Sorting by x1 coordinate and walk by the bounds in the same order.
|
||||
bounds.sort(function (a, b) {
|
||||
bounds.sort(function(a, b) {
|
||||
return a.x1 - b.x1 || a.index - b.index;
|
||||
});
|
||||
|
||||
@ -305,13 +310,15 @@ var renderTextLayer = (function renderTextLayerClosure() {
|
||||
x1New: 0,
|
||||
x2New: 0,
|
||||
};
|
||||
var horizon = [{
|
||||
start: -Infinity,
|
||||
end: Infinity,
|
||||
boundary: fakeBoundary,
|
||||
}];
|
||||
var horizon = [
|
||||
{
|
||||
start: -Infinity,
|
||||
end: Infinity,
|
||||
boundary: fakeBoundary,
|
||||
},
|
||||
];
|
||||
|
||||
bounds.forEach(function (boundary) {
|
||||
bounds.forEach(function(boundary) {
|
||||
// Searching for the affected part of horizon.
|
||||
// TODO red-black tree or simple binary search
|
||||
var i = 0;
|
||||
@ -324,7 +331,9 @@ var renderTextLayer = (function renderTextLayerClosure() {
|
||||
}
|
||||
|
||||
var horizonPart, affectedBoundary;
|
||||
var q, k, maxXNew = -Infinity;
|
||||
var q,
|
||||
k,
|
||||
maxXNew = -Infinity;
|
||||
for (q = i; q <= j; q++) {
|
||||
horizonPart = horizon[q];
|
||||
affectedBoundary = horizonPart.boundary;
|
||||
@ -333,8 +342,10 @@ var renderTextLayer = (function renderTextLayerClosure() {
|
||||
// In the middle of the previous element, new x shall be at the
|
||||
// boundary start. Extending if further if the affected boundary
|
||||
// placed on top of the current one.
|
||||
xNew = affectedBoundary.index > boundary.index ?
|
||||
affectedBoundary.x1New : boundary.x1;
|
||||
xNew =
|
||||
affectedBoundary.index > boundary.index
|
||||
? affectedBoundary.x1New
|
||||
: boundary.x1;
|
||||
} else if (affectedBoundary.x2New === undefined) {
|
||||
// We have some space in between, new x in middle will be a fair
|
||||
// choice.
|
||||
@ -373,13 +384,14 @@ var renderTextLayer = (function renderTextLayerClosure() {
|
||||
}
|
||||
|
||||
// Fixing the horizon.
|
||||
var changedHorizon = [], lastBoundary = null;
|
||||
var changedHorizon = [],
|
||||
lastBoundary = null;
|
||||
for (q = i; q <= j; q++) {
|
||||
horizonPart = horizon[q];
|
||||
affectedBoundary = horizonPart.boundary;
|
||||
// Checking which boundary will be visible.
|
||||
var useBoundary = affectedBoundary.x2 > boundary.x2 ?
|
||||
affectedBoundary : boundary;
|
||||
var useBoundary =
|
||||
affectedBoundary.x2 > boundary.x2 ? affectedBoundary : boundary;
|
||||
if (lastBoundary === useBoundary) {
|
||||
// Merging with previous.
|
||||
changedHorizon[changedHorizon.length - 1].end = horizonPart.end;
|
||||
@ -419,12 +431,18 @@ var renderTextLayer = (function renderTextLayerClosure() {
|
||||
continue;
|
||||
}
|
||||
var used = false;
|
||||
for (k = i - 1; !used && k >= 0 &&
|
||||
horizon[k].start >= affectedBoundary.y1; k--) {
|
||||
for (
|
||||
k = i - 1;
|
||||
!used && k >= 0 && horizon[k].start >= affectedBoundary.y1;
|
||||
k--
|
||||
) {
|
||||
used = horizon[k].boundary === affectedBoundary;
|
||||
}
|
||||
for (k = j + 1; !used && k < horizon.length &&
|
||||
horizon[k].end <= affectedBoundary.y2; k++) {
|
||||
for (
|
||||
k = j + 1;
|
||||
!used && k < horizon.length && horizon[k].end <= affectedBoundary.y2;
|
||||
k++
|
||||
) {
|
||||
used = horizon[k].boundary === affectedBoundary;
|
||||
}
|
||||
for (k = 0; !used && k < changedHorizon.length; k++) {
|
||||
@ -435,12 +453,14 @@ var renderTextLayer = (function renderTextLayerClosure() {
|
||||
}
|
||||
}
|
||||
|
||||
Array.prototype.splice.apply(horizon,
|
||||
[i, j - i + 1].concat(changedHorizon));
|
||||
Array.prototype.splice.apply(
|
||||
horizon,
|
||||
[i, j - i + 1].concat(changedHorizon)
|
||||
);
|
||||
});
|
||||
|
||||
// Set new x2 for all unset boundaries.
|
||||
horizon.forEach(function (horizonPart) {
|
||||
horizon.forEach(function(horizonPart) {
|
||||
var affectedBoundary = horizonPart.boundary;
|
||||
if (affectedBoundary.x2New === undefined) {
|
||||
affectedBoundary.x2New = Math.max(width, affectedBoundary.x2);
|
||||
@ -458,9 +478,15 @@ var renderTextLayer = (function renderTextLayerClosure() {
|
||||
* @param {boolean} enhanceTextSelection
|
||||
* @private
|
||||
*/
|
||||
function TextLayerRenderTask({ textContent, textContentStream, container,
|
||||
viewport, textDivs, textContentItemsStr,
|
||||
enhanceTextSelection, }) {
|
||||
function TextLayerRenderTask({
|
||||
textContent,
|
||||
textContentStream,
|
||||
container,
|
||||
viewport,
|
||||
textDivs,
|
||||
textContentItemsStr,
|
||||
enhanceTextSelection,
|
||||
}) {
|
||||
this._textContent = textContent;
|
||||
this._textContentStream = textContentStream;
|
||||
this._container = container;
|
||||
@ -468,8 +494,9 @@ var renderTextLayer = (function renderTextLayerClosure() {
|
||||
this._textDivs = textDivs || [];
|
||||
this._textContentItemsStr = textContentItemsStr || [];
|
||||
this._enhanceTextSelection = !!enhanceTextSelection;
|
||||
this._fontInspectorEnabled = !!(globalThis.FontInspector &&
|
||||
globalThis.FontInspector.enabled);
|
||||
this._fontInspectorEnabled = !!(
|
||||
globalThis.FontInspector && globalThis.FontInspector.enabled
|
||||
);
|
||||
|
||||
this._reader = null;
|
||||
this._layoutTextLastFontSize = null;
|
||||
@ -483,15 +510,19 @@ var renderTextLayer = (function renderTextLayerClosure() {
|
||||
this._bounds = [];
|
||||
|
||||
// Always clean-up the temporary canvas once rendering is no longer pending.
|
||||
this._capability.promise.finally(() => {
|
||||
if (this._layoutTextCtx) {
|
||||
// Zeroing the width and height cause Firefox to release graphics
|
||||
// resources immediately, which can greatly reduce memory consumption.
|
||||
this._layoutTextCtx.canvas.width = 0;
|
||||
this._layoutTextCtx.canvas.height = 0;
|
||||
this._layoutTextCtx = null;
|
||||
}
|
||||
}).catch(() => { /* Avoid "Uncaught promise" messages in the console. */ });
|
||||
this._capability.promise
|
||||
.finally(() => {
|
||||
if (this._layoutTextCtx) {
|
||||
// Zeroing the width and height cause Firefox to release graphics
|
||||
// resources immediately, which can greatly reduce memory consumption.
|
||||
this._layoutTextCtx.canvas.width = 0;
|
||||
this._layoutTextCtx.canvas.height = 0;
|
||||
this._layoutTextCtx = null;
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
/* Avoid "Uncaught promise" messages in the console. */
|
||||
});
|
||||
}
|
||||
TextLayerRenderTask.prototype = {
|
||||
get promise() {
|
||||
@ -501,14 +532,14 @@ var renderTextLayer = (function renderTextLayerClosure() {
|
||||
cancel: function TextLayer_cancel() {
|
||||
this._canceled = true;
|
||||
if (this._reader) {
|
||||
this._reader.cancel(new AbortException('TextLayer task cancelled.'));
|
||||
this._reader.cancel(new AbortException("TextLayer task cancelled."));
|
||||
this._reader = null;
|
||||
}
|
||||
if (this._renderTimer !== null) {
|
||||
clearTimeout(this._renderTimer);
|
||||
this._renderTimer = null;
|
||||
}
|
||||
this._capability.reject(new Error('TextLayer task cancelled.'));
|
||||
this._capability.reject(new Error("TextLayer task cancelled."));
|
||||
},
|
||||
|
||||
_processItems(items, styleCache) {
|
||||
@ -524,19 +555,21 @@ var renderTextLayer = (function renderTextLayerClosure() {
|
||||
return;
|
||||
}
|
||||
|
||||
let transform = '';
|
||||
let transform = "";
|
||||
if (textDivProperties.canvasWidth !== 0) {
|
||||
const { fontSize, fontFamily, } = textDiv.style;
|
||||
const { fontSize, fontFamily } = textDiv.style;
|
||||
|
||||
// Only build font string and set to context if different from last.
|
||||
if (fontSize !== this._layoutTextLastFontSize ||
|
||||
fontFamily !== this._layoutTextLastFontFamily) {
|
||||
if (
|
||||
fontSize !== this._layoutTextLastFontSize ||
|
||||
fontFamily !== this._layoutTextLastFontFamily
|
||||
) {
|
||||
this._layoutTextCtx.font = `${fontSize} ${fontFamily}`;
|
||||
this._layoutTextLastFontSize = fontSize;
|
||||
this._layoutTextLastFontFamily = fontFamily;
|
||||
}
|
||||
// Only measure the width for multi-char text divs, see `appendText`.
|
||||
const { width, } = this._layoutTextCtx.measureText(textDiv.textContent);
|
||||
const { width } = this._layoutTextCtx.measureText(textDiv.textContent);
|
||||
|
||||
if (width > 0) {
|
||||
textDivProperties.scale = textDivProperties.canvasWidth / width;
|
||||
@ -561,12 +594,14 @@ var renderTextLayer = (function renderTextLayerClosure() {
|
||||
let styleCache = Object.create(null);
|
||||
|
||||
// The temporary canvas is used to measure text length in the DOM.
|
||||
let canvas = document.createElement('canvas');
|
||||
if (typeof PDFJSDev === 'undefined' ||
|
||||
PDFJSDev.test('FIREFOX || MOZCENTRAL || GENERIC')) {
|
||||
canvas.mozOpaque = true;
|
||||
let canvas = document.createElement("canvas");
|
||||
if (
|
||||
typeof PDFJSDev === "undefined" ||
|
||||
PDFJSDev.test("FIREFOX || MOZCENTRAL || GENERIC")
|
||||
) {
|
||||
canvas.mozOpaque = true;
|
||||
}
|
||||
this._layoutTextCtx = canvas.getContext('2d', { alpha: false, });
|
||||
this._layoutTextCtx = canvas.getContext("2d", { alpha: false });
|
||||
|
||||
if (this._textContent) {
|
||||
let textItems = this._textContent.items;
|
||||
@ -575,7 +610,7 @@ var renderTextLayer = (function renderTextLayerClosure() {
|
||||
capability.resolve();
|
||||
} else if (this._textContentStream) {
|
||||
let pump = () => {
|
||||
this._reader.read().then(({ value, done, }) => {
|
||||
this._reader.read().then(({ value, done }) => {
|
||||
if (done) {
|
||||
capability.resolve();
|
||||
return;
|
||||
@ -590,15 +625,19 @@ var renderTextLayer = (function renderTextLayerClosure() {
|
||||
this._reader = this._textContentStream.getReader();
|
||||
pump();
|
||||
} else {
|
||||
throw new Error('Neither "textContent" nor "textContentStream"' +
|
||||
' parameters specified.');
|
||||
throw new Error(
|
||||
'Neither "textContent" nor "textContentStream"' +
|
||||
" parameters specified."
|
||||
);
|
||||
}
|
||||
|
||||
capability.promise.then(() => {
|
||||
styleCache = null;
|
||||
if (!timeout) { // Render right away
|
||||
if (!timeout) {
|
||||
// Render right away
|
||||
render(this);
|
||||
} else { // Schedule
|
||||
} else {
|
||||
// Schedule
|
||||
this._renderTimer = setTimeout(() => {
|
||||
render(this);
|
||||
this._renderTimer = null;
|
||||
@ -615,8 +654,9 @@ var renderTextLayer = (function renderTextLayerClosure() {
|
||||
expand(this);
|
||||
this._bounds = null;
|
||||
}
|
||||
const NO_PADDING = '0 0 0 0';
|
||||
const transformBuf = [], paddingBuf = [];
|
||||
const NO_PADDING = "0 0 0 0";
|
||||
const transformBuf = [],
|
||||
paddingBuf = [];
|
||||
|
||||
for (var i = 0, ii = this._textDivs.length; i < ii; i++) {
|
||||
const div = this._textDivs[i];
|
||||
@ -651,17 +691,18 @@ var renderTextLayer = (function renderTextLayerClosure() {
|
||||
if (divProps.paddingLeft > 0) {
|
||||
paddingBuf.push(`${divProps.paddingLeft / divProps.scale}px`);
|
||||
transformBuf.push(
|
||||
`translateX(${-divProps.paddingLeft / divProps.scale}px)`);
|
||||
`translateX(${-divProps.paddingLeft / divProps.scale}px)`
|
||||
);
|
||||
} else {
|
||||
paddingBuf.push(0);
|
||||
}
|
||||
|
||||
const padding = paddingBuf.join(' ');
|
||||
const padding = paddingBuf.join(" ");
|
||||
if (padding !== NO_PADDING) {
|
||||
div.style.padding = padding;
|
||||
}
|
||||
if (transformBuf.length) {
|
||||
div.style.transform = transformBuf.join(' ');
|
||||
div.style.transform = transformBuf.join(" ");
|
||||
}
|
||||
} else {
|
||||
div.style.padding = null;
|
||||
@ -694,6 +735,4 @@ var renderTextLayer = (function renderTextLayerClosure() {
|
||||
return renderTextLayer;
|
||||
})();
|
||||
|
||||
export {
|
||||
renderTextLayer,
|
||||
};
|
||||
export { renderTextLayer };
|
||||
|
@ -14,7 +14,7 @@
|
||||
*/
|
||||
/* eslint no-var: error */
|
||||
|
||||
import { assert, createPromiseCapability } from '../shared/util';
|
||||
import { assert, createPromiseCapability } from "../shared/util";
|
||||
|
||||
/** @implements {IPDFStream} */
|
||||
class PDFDataTransportStream {
|
||||
@ -39,15 +39,15 @@ class PDFDataTransportStream {
|
||||
this._rangeReaders = [];
|
||||
|
||||
this._pdfDataRangeTransport.addRangeListener((begin, chunk) => {
|
||||
this._onReceiveData({ begin, chunk, });
|
||||
this._onReceiveData({ begin, chunk });
|
||||
});
|
||||
|
||||
this._pdfDataRangeTransport.addProgressListener((loaded, total) => {
|
||||
this._onProgress({ loaded, total, });
|
||||
this._onProgress({ loaded, total });
|
||||
});
|
||||
|
||||
this._pdfDataRangeTransport.addProgressiveReadListener((chunk) => {
|
||||
this._onReceiveData({ chunk, });
|
||||
this._pdfDataRangeTransport.addProgressiveReadListener(chunk => {
|
||||
this._onReceiveData({ chunk });
|
||||
});
|
||||
|
||||
this._pdfDataRangeTransport.addProgressiveDoneListener(() => {
|
||||
@ -78,7 +78,7 @@ class PDFDataTransportStream {
|
||||
}
|
||||
|
||||
get _progressiveDataLength() {
|
||||
return (this._fullRequestReader ? this._fullRequestReader._loaded : 0);
|
||||
return this._fullRequestReader ? this._fullRequestReader._loaded : 0;
|
||||
}
|
||||
|
||||
_onProgress(evt) {
|
||||
@ -86,12 +86,12 @@ class PDFDataTransportStream {
|
||||
// Reporting to first range reader, if it exists.
|
||||
const firstReader = this._rangeReaders[0];
|
||||
if (firstReader && firstReader.onProgress) {
|
||||
firstReader.onProgress({ loaded: evt.loaded, });
|
||||
firstReader.onProgress({ loaded: evt.loaded });
|
||||
}
|
||||
} else {
|
||||
const fullReader = this._fullRequestReader;
|
||||
if (fullReader && fullReader.onProgress) {
|
||||
fullReader.onProgress({ loaded: evt.loaded, total: evt.total, });
|
||||
fullReader.onProgress({ loaded: evt.loaded, total: evt.total });
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -114,8 +114,11 @@ class PDFDataTransportStream {
|
||||
assert(!this._fullRequestReader);
|
||||
const queuedChunks = this._queuedChunks;
|
||||
this._queuedChunks = null;
|
||||
return new PDFDataTransportStreamReader(this, queuedChunks,
|
||||
this._progressiveDone);
|
||||
return new PDFDataTransportStreamReader(
|
||||
this,
|
||||
queuedChunks,
|
||||
this._progressiveDone
|
||||
);
|
||||
}
|
||||
|
||||
getRangeReader(begin, end) {
|
||||
@ -164,7 +167,7 @@ class PDFDataTransportStreamReader {
|
||||
}
|
||||
if (this._requests.length > 0) {
|
||||
const requestCapability = this._requests.shift();
|
||||
requestCapability.resolve({ value: chunk, done: false, });
|
||||
requestCapability.resolve({ value: chunk, done: false });
|
||||
} else {
|
||||
this._queuedChunks.push(chunk);
|
||||
}
|
||||
@ -194,10 +197,10 @@ class PDFDataTransportStreamReader {
|
||||
async read() {
|
||||
if (this._queuedChunks.length > 0) {
|
||||
const chunk = this._queuedChunks.shift();
|
||||
return { value: chunk, done: false, };
|
||||
return { value: chunk, done: false };
|
||||
}
|
||||
if (this._done) {
|
||||
return { value: undefined, done: true, };
|
||||
return { value: undefined, done: true };
|
||||
}
|
||||
const requestCapability = createPromiseCapability();
|
||||
this._requests.push(requestCapability);
|
||||
@ -207,7 +210,7 @@ class PDFDataTransportStreamReader {
|
||||
cancel(reason) {
|
||||
this._done = true;
|
||||
this._requests.forEach(function(requestCapability) {
|
||||
requestCapability.resolve({ value: undefined, done: true, });
|
||||
requestCapability.resolve({ value: undefined, done: true });
|
||||
});
|
||||
this._requests = [];
|
||||
}
|
||||
@ -241,9 +244,9 @@ class PDFDataTransportStreamRangeReader {
|
||||
this._queuedChunk = chunk;
|
||||
} else {
|
||||
const requestsCapability = this._requests.shift();
|
||||
requestsCapability.resolve({ value: chunk, done: false, });
|
||||
requestsCapability.resolve({ value: chunk, done: false });
|
||||
this._requests.forEach(function(requestCapability) {
|
||||
requestCapability.resolve({ value: undefined, done: true, });
|
||||
requestCapability.resolve({ value: undefined, done: true });
|
||||
});
|
||||
this._requests = [];
|
||||
}
|
||||
@ -259,10 +262,10 @@ class PDFDataTransportStreamRangeReader {
|
||||
if (this._queuedChunk) {
|
||||
const chunk = this._queuedChunk;
|
||||
this._queuedChunk = null;
|
||||
return { value: chunk, done: false, };
|
||||
return { value: chunk, done: false };
|
||||
}
|
||||
if (this._done) {
|
||||
return { value: undefined, done: true, };
|
||||
return { value: undefined, done: true };
|
||||
}
|
||||
const requestCapability = createPromiseCapability();
|
||||
this._requests.push(requestCapability);
|
||||
@ -272,13 +275,11 @@ class PDFDataTransportStreamRangeReader {
|
||||
cancel(reason) {
|
||||
this._done = true;
|
||||
this._requests.forEach(function(requestCapability) {
|
||||
requestCapability.resolve({ value: undefined, done: true, });
|
||||
requestCapability.resolve({ value: undefined, done: true });
|
||||
});
|
||||
this._requests = [];
|
||||
this._stream._removeRangeReader(this);
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
PDFDataTransportStream,
|
||||
};
|
||||
export { PDFDataTransportStream };
|
||||
|
@ -14,10 +14,10 @@
|
||||
*/
|
||||
/* eslint-disable no-multi-str */
|
||||
|
||||
import { shadow } from '../shared/util';
|
||||
import { shadow } from "../shared/util";
|
||||
|
||||
class WebGLContext {
|
||||
constructor({ enable = false, }) {
|
||||
constructor({ enable = false }) {
|
||||
this._enabled = enable === true;
|
||||
}
|
||||
|
||||
@ -26,16 +26,21 @@ class WebGLContext {
|
||||
if (enabled) {
|
||||
enabled = WebGLUtils.tryInitGL();
|
||||
}
|
||||
return shadow(this, 'isEnabled', enabled);
|
||||
return shadow(this, "isEnabled", enabled);
|
||||
}
|
||||
|
||||
composeSMask({ layer, mask, properties, }) {
|
||||
composeSMask({ layer, mask, properties }) {
|
||||
return WebGLUtils.composeSMask(layer, mask, properties);
|
||||
}
|
||||
|
||||
drawFigures({ width, height, backgroundColor, figures, context, }) {
|
||||
return WebGLUtils.drawFigures(width, height, backgroundColor, figures,
|
||||
context);
|
||||
drawFigures({ width, height, backgroundColor, figures, context }) {
|
||||
return WebGLUtils.drawFigures(
|
||||
width,
|
||||
height,
|
||||
backgroundColor,
|
||||
figures,
|
||||
context
|
||||
);
|
||||
}
|
||||
|
||||
clear() {
|
||||
@ -51,7 +56,7 @@ var WebGLUtils = (function WebGLUtilsClosure() {
|
||||
var compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
|
||||
if (!compiled) {
|
||||
var errorMsg = gl.getShaderInfoLog(shader);
|
||||
throw new Error('Error during shader compilation: ' + errorMsg);
|
||||
throw new Error("Error during shader compilation: " + errorMsg);
|
||||
}
|
||||
return shader;
|
||||
}
|
||||
@ -70,7 +75,7 @@ var WebGLUtils = (function WebGLUtilsClosure() {
|
||||
var linked = gl.getProgramParameter(program, gl.LINK_STATUS);
|
||||
if (!linked) {
|
||||
var errorMsg = gl.getProgramInfoLog(program);
|
||||
throw new Error('Error during program linking: ' + errorMsg);
|
||||
throw new Error("Error during program linking: " + errorMsg);
|
||||
}
|
||||
return program;
|
||||
}
|
||||
@ -97,12 +102,14 @@ var WebGLUtils = (function WebGLUtilsClosure() {
|
||||
}
|
||||
|
||||
// The temporary canvas is used in the WebGL context.
|
||||
currentCanvas = document.createElement('canvas');
|
||||
currentGL = currentCanvas.getContext('webgl',
|
||||
{ premultipliedalpha: false, });
|
||||
currentCanvas = document.createElement("canvas");
|
||||
currentGL = currentCanvas.getContext("webgl", {
|
||||
premultipliedalpha: false,
|
||||
});
|
||||
}
|
||||
|
||||
var smaskVertexShaderCode = '\
|
||||
var smaskVertexShaderCode =
|
||||
"\
|
||||
attribute vec2 a_position; \
|
||||
attribute vec2 a_texCoord; \
|
||||
\
|
||||
@ -115,9 +122,10 @@ var WebGLUtils = (function WebGLUtilsClosure() {
|
||||
gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1); \
|
||||
\
|
||||
v_texCoord = a_texCoord; \
|
||||
} ';
|
||||
} ";
|
||||
|
||||
var smaskFragmentShaderCode = '\
|
||||
var smaskFragmentShaderCode =
|
||||
"\
|
||||
precision mediump float; \
|
||||
\
|
||||
uniform vec4 u_backdrop; \
|
||||
@ -144,7 +152,7 @@ var WebGLUtils = (function WebGLUtilsClosure() {
|
||||
imageColor.a *= lum; \
|
||||
imageColor.rgb *= imageColor.a; \
|
||||
gl_FragColor = imageColor; \
|
||||
} ';
|
||||
} ";
|
||||
|
||||
var smaskCache = null;
|
||||
|
||||
@ -166,18 +174,19 @@ var WebGLUtils = (function WebGLUtilsClosure() {
|
||||
var cache = {};
|
||||
cache.gl = gl;
|
||||
cache.canvas = canvas;
|
||||
cache.resolutionLocation = gl.getUniformLocation(program, 'u_resolution');
|
||||
cache.positionLocation = gl.getAttribLocation(program, 'a_position');
|
||||
cache.backdropLocation = gl.getUniformLocation(program, 'u_backdrop');
|
||||
cache.subtypeLocation = gl.getUniformLocation(program, 'u_subtype');
|
||||
cache.resolutionLocation = gl.getUniformLocation(program, "u_resolution");
|
||||
cache.positionLocation = gl.getAttribLocation(program, "a_position");
|
||||
cache.backdropLocation = gl.getUniformLocation(program, "u_backdrop");
|
||||
cache.subtypeLocation = gl.getUniformLocation(program, "u_subtype");
|
||||
|
||||
var texCoordLocation = gl.getAttribLocation(program, 'a_texCoord');
|
||||
var texLayerLocation = gl.getUniformLocation(program, 'u_image');
|
||||
var texMaskLocation = gl.getUniformLocation(program, 'u_mask');
|
||||
var texCoordLocation = gl.getAttribLocation(program, "a_texCoord");
|
||||
var texLayerLocation = gl.getUniformLocation(program, "u_image");
|
||||
var texMaskLocation = gl.getUniformLocation(program, "u_mask");
|
||||
|
||||
// provide texture coordinates for the rectangle.
|
||||
var texCoordBuffer = gl.createBuffer();
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
|
||||
// prettier-ignore
|
||||
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
|
||||
0.0, 0.0,
|
||||
1.0, 0.0,
|
||||
@ -195,25 +204,35 @@ var WebGLUtils = (function WebGLUtilsClosure() {
|
||||
}
|
||||
|
||||
function composeSMask(layer, mask, properties) {
|
||||
var width = layer.width, height = layer.height;
|
||||
var width = layer.width,
|
||||
height = layer.height;
|
||||
|
||||
if (!smaskCache) {
|
||||
initSmaskGL();
|
||||
}
|
||||
var cache = smaskCache, canvas = cache.canvas, gl = cache.gl;
|
||||
var cache = smaskCache,
|
||||
canvas = cache.canvas,
|
||||
gl = cache.gl;
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
|
||||
gl.uniform2f(cache.resolutionLocation, width, height);
|
||||
|
||||
if (properties.backdrop) {
|
||||
gl.uniform4f(cache.resolutionLocation, properties.backdrop[0],
|
||||
properties.backdrop[1], properties.backdrop[2], 1);
|
||||
gl.uniform4f(
|
||||
cache.resolutionLocation,
|
||||
properties.backdrop[0],
|
||||
properties.backdrop[1],
|
||||
properties.backdrop[2],
|
||||
1
|
||||
);
|
||||
} else {
|
||||
gl.uniform4f(cache.resolutionLocation, 0, 0, 0, 0);
|
||||
}
|
||||
gl.uniform1i(cache.subtypeLocation,
|
||||
properties.subtype === 'Luminosity' ? 1 : 0);
|
||||
gl.uniform1i(
|
||||
cache.subtypeLocation,
|
||||
properties.subtype === "Luminosity" ? 1 : 0
|
||||
);
|
||||
|
||||
// Create a textures
|
||||
var texture = createTexture(gl, layer, gl.TEXTURE0);
|
||||
@ -223,6 +242,7 @@ var WebGLUtils = (function WebGLUtilsClosure() {
|
||||
// it (2 triangles)
|
||||
var buffer = gl.createBuffer();
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
|
||||
// prettier-ignore
|
||||
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
|
||||
0, 0,
|
||||
width, 0,
|
||||
@ -250,7 +270,8 @@ var WebGLUtils = (function WebGLUtilsClosure() {
|
||||
return canvas;
|
||||
}
|
||||
|
||||
var figuresVertexShaderCode = '\
|
||||
var figuresVertexShaderCode =
|
||||
"\
|
||||
attribute vec2 a_position; \
|
||||
attribute vec3 a_color; \
|
||||
\
|
||||
@ -266,16 +287,17 @@ var WebGLUtils = (function WebGLUtilsClosure() {
|
||||
gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1); \
|
||||
\
|
||||
v_color = vec4(a_color / 255.0, 1.0); \
|
||||
} ';
|
||||
} ";
|
||||
|
||||
var figuresFragmentShaderCode = '\
|
||||
var figuresFragmentShaderCode =
|
||||
"\
|
||||
precision mediump float; \
|
||||
\
|
||||
varying vec4 v_color; \
|
||||
\
|
||||
void main() { \
|
||||
gl_FragColor = v_color; \
|
||||
} ';
|
||||
} ";
|
||||
|
||||
var figuresCache = null;
|
||||
|
||||
@ -297,11 +319,11 @@ var WebGLUtils = (function WebGLUtilsClosure() {
|
||||
var cache = {};
|
||||
cache.gl = gl;
|
||||
cache.canvas = canvas;
|
||||
cache.resolutionLocation = gl.getUniformLocation(program, 'u_resolution');
|
||||
cache.scaleLocation = gl.getUniformLocation(program, 'u_scale');
|
||||
cache.offsetLocation = gl.getUniformLocation(program, 'u_offset');
|
||||
cache.positionLocation = gl.getAttribLocation(program, 'a_position');
|
||||
cache.colorLocation = gl.getAttribLocation(program, 'a_color');
|
||||
cache.resolutionLocation = gl.getUniformLocation(program, "u_resolution");
|
||||
cache.scaleLocation = gl.getUniformLocation(program, "u_scale");
|
||||
cache.offsetLocation = gl.getUniformLocation(program, "u_offset");
|
||||
cache.positionLocation = gl.getAttribLocation(program, "a_position");
|
||||
cache.colorLocation = gl.getAttribLocation(program, "a_color");
|
||||
|
||||
figuresCache = cache;
|
||||
}
|
||||
@ -310,7 +332,9 @@ var WebGLUtils = (function WebGLUtilsClosure() {
|
||||
if (!figuresCache) {
|
||||
initFiguresGL();
|
||||
}
|
||||
var cache = figuresCache, canvas = cache.canvas, gl = cache.gl;
|
||||
var cache = figuresCache,
|
||||
canvas = cache.canvas,
|
||||
gl = cache.gl;
|
||||
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
@ -322,11 +346,11 @@ var WebGLUtils = (function WebGLUtilsClosure() {
|
||||
var i, ii, rows;
|
||||
for (i = 0, ii = figures.length; i < ii; i++) {
|
||||
switch (figures[i].type) {
|
||||
case 'lattice':
|
||||
case "lattice":
|
||||
rows = (figures[i].coords.length / figures[i].verticesPerRow) | 0;
|
||||
count += (rows - 1) * (figures[i].verticesPerRow - 1) * 6;
|
||||
break;
|
||||
case 'triangles':
|
||||
case "triangles":
|
||||
count += figures[i].coords.length;
|
||||
break;
|
||||
}
|
||||
@ -334,12 +358,16 @@ var WebGLUtils = (function WebGLUtilsClosure() {
|
||||
// transfer data
|
||||
var coords = new Float32Array(count * 2);
|
||||
var colors = new Uint8Array(count * 3);
|
||||
var coordsMap = context.coords, colorsMap = context.colors;
|
||||
var pIndex = 0, cIndex = 0;
|
||||
var coordsMap = context.coords,
|
||||
colorsMap = context.colors;
|
||||
var pIndex = 0,
|
||||
cIndex = 0;
|
||||
for (i = 0, ii = figures.length; i < ii; i++) {
|
||||
var figure = figures[i], ps = figure.coords, cs = figure.colors;
|
||||
var figure = figures[i],
|
||||
ps = figure.coords,
|
||||
cs = figure.colors;
|
||||
switch (figure.type) {
|
||||
case 'lattice':
|
||||
case "lattice":
|
||||
var cols = figure.verticesPerRow;
|
||||
rows = (ps.length / cols) | 0;
|
||||
for (var row = 1; row < rows; row++) {
|
||||
@ -381,7 +409,7 @@ var WebGLUtils = (function WebGLUtilsClosure() {
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'triangles':
|
||||
case "triangles":
|
||||
for (var j = 0, jj = ps.length; j < jj; j++) {
|
||||
coords[pIndex] = coordsMap[ps[j]];
|
||||
coords[pIndex + 1] = coordsMap[ps[j] + 1];
|
||||
@ -397,8 +425,12 @@ var WebGLUtils = (function WebGLUtilsClosure() {
|
||||
|
||||
// draw
|
||||
if (backgroundColor) {
|
||||
gl.clearColor(backgroundColor[0] / 255, backgroundColor[1] / 255,
|
||||
backgroundColor[2] / 255, 1.0);
|
||||
gl.clearColor(
|
||||
backgroundColor[0] / 255,
|
||||
backgroundColor[1] / 255,
|
||||
backgroundColor[2] / 255,
|
||||
1.0
|
||||
);
|
||||
} else {
|
||||
gl.clearColor(0, 0, 0, 0);
|
||||
}
|
||||
@ -414,8 +446,14 @@ var WebGLUtils = (function WebGLUtilsClosure() {
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, colorsBuffer);
|
||||
gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW);
|
||||
gl.enableVertexAttribArray(cache.colorLocation);
|
||||
gl.vertexAttribPointer(cache.colorLocation, 3, gl.UNSIGNED_BYTE, false,
|
||||
0, 0);
|
||||
gl.vertexAttribPointer(
|
||||
cache.colorLocation,
|
||||
3,
|
||||
gl.UNSIGNED_BYTE,
|
||||
false,
|
||||
0,
|
||||
0
|
||||
);
|
||||
|
||||
gl.uniform2f(cache.scaleLocation, context.scaleX, context.scaleY);
|
||||
gl.uniform2f(cache.offsetLocation, context.offsetX, context.offsetY);
|
||||
@ -435,7 +473,7 @@ var WebGLUtils = (function WebGLUtilsClosure() {
|
||||
try {
|
||||
generateGL();
|
||||
return !!currentGL;
|
||||
} catch (ex) { }
|
||||
} catch (ex) {}
|
||||
return false;
|
||||
},
|
||||
|
||||
@ -458,6 +496,4 @@ var WebGLUtils = (function WebGLUtilsClosure() {
|
||||
};
|
||||
})();
|
||||
|
||||
export {
|
||||
WebGLContext,
|
||||
};
|
||||
export { WebGLContext };
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user