diff --git a/examples/acroforms/acroforms.js b/examples/acroforms/acroforms.js index 44932e796..a54494534 100644 --- a/examples/acroforms/acroforms.js +++ b/examples/acroforms/acroforms.js @@ -15,7 +15,7 @@ 'use strict'; -PDFJS.GlobalWorkerOptions.workerSrc = +pdfjsDistBuildPdf.GlobalWorkerOptions.workerSrc = '../../node_modules/pdfjs-dist/build/pdf.worker.js'; var DEFAULT_URL = '../../test/pdfs/f1040.pdf'; @@ -24,7 +24,7 @@ var DEFAULT_SCALE = 1.0; var container = document.getElementById('pageContainer'); // Fetch the PDF document from the URL using promises. -PDFJS.getDocument(DEFAULT_URL).then(function (doc) { +pdfjsDistBuildPdf.getDocument(DEFAULT_URL).then(function (doc) { // Use a promise to fetch and render the next page. var promise = Promise.resolve(); @@ -32,12 +32,12 @@ PDFJS.getDocument(DEFAULT_URL).then(function (doc) { promise = promise.then(function (pageNum) { return doc.getPage(pageNum).then(function (pdfPage) { // Create the page view. - var pdfPageView = new PDFJS.PDFPageView({ + var pdfPageView = new pdfjsDistWebPdfViewer.PDFPageView({ container: container, id: pageNum, scale: DEFAULT_SCALE, defaultViewport: pdfPage.getViewport(DEFAULT_SCALE), - annotationLayerFactory: new PDFJS.DefaultAnnotationLayerFactory(), + annotationLayerFactory: new pdfjsDistWebPdfViewer.DefaultAnnotationLayerFactory(), renderInteractiveForms: true, }); diff --git a/examples/browserify/main.js b/examples/browserify/main.js index 5d20aa05b..218a8c0e5 100644 --- a/examples/browserify/main.js +++ b/examples/browserify/main.js @@ -3,16 +3,16 @@ // Hello world example for browserify. -require('pdfjs-dist'); +var pdfjsLib = require('pdfjs-dist'); var pdfPath = '../helloworld/helloworld.pdf'; // Setting worker path to worker bundle. -PDFJS.GlobalWorkerOptions.workerSrc = +pdfjsLib.GlobalWorkerOptions.workerSrc = '../../build/browserify/pdf.worker.bundle.js'; // Loading a document. -var loadingTask = PDFJS.getDocument(pdfPath); +var loadingTask = pdfjsLib.getDocument(pdfPath); loadingTask.promise.then(function (pdfDocument) { // Request a first page return pdfDocument.getPage(1).then(function (pdfPage) { diff --git a/examples/components/pageviewer.js b/examples/components/pageviewer.js index 0d128ebc9..63d317560 100644 --- a/examples/components/pageviewer.js +++ b/examples/components/pageviewer.js @@ -15,20 +15,20 @@ 'use strict'; -if (!PDFJS.PDFViewer || !PDFJS.getDocument) { +if (!pdfjsDistBuildPdf.getDocument || !pdfjsDistWebPdfViewer.PDFPageView) { alert('Please build the pdfjs-dist library using\n' + ' `gulp dist-install`'); } // The workerSrc property shall be specified. // -PDFJS.GlobalWorkerOptions.workerSrc = +pdfjsDistBuildPdf.GlobalWorkerOptions.workerSrc = '../../node_modules/pdfjs-dist/build/pdf.worker.js'; // Some PDFs need external cmaps. // -// PDFJS.cMapUrl = '../../node_modules/pdfjs-dist/cmaps/'; -// PDFJS.cMapPacked = true; +var CMAP_URL = '../../node_modules/pdfjs-dist/cmaps/'; +var CMAP_PACKED = true; var DEFAULT_URL = '../../web/compressed.tracemonkey-pldi-09.pdf'; var PAGE_TO_VIEW = 1; @@ -37,18 +37,22 @@ var SCALE = 1.0; var container = document.getElementById('pageContainer'); // Loading document. -PDFJS.getDocument(DEFAULT_URL).then(function (pdfDocument) { +pdfjsDistBuildPdf.getDocument({ + url: DEFAULT_URL, + cMapUrl: CMAP_URL, + cMapPacked: CMAP_PACKED, +}).then(function(pdfDocument) { // Document loaded, retrieving the page. return pdfDocument.getPage(PAGE_TO_VIEW).then(function (pdfPage) { // Creating the page view with default parameters. - var pdfPageView = new PDFJS.PDFPageView({ + var pdfPageView = new pdfjsDistWebPdfViewer.PDFPageView({ container: container, id: PAGE_TO_VIEW, scale: SCALE, defaultViewport: pdfPage.getViewport(SCALE), // We can enable text/annotations layers, if needed - textLayerFactory: new PDFJS.DefaultTextLayerFactory(), - annotationLayerFactory: new PDFJS.DefaultAnnotationLayerFactory() + textLayerFactory: new pdfjsDistWebPdfViewer.DefaultTextLayerFactory(), + annotationLayerFactory: new pdfjsDistWebPdfViewer.DefaultAnnotationLayerFactory(), }); // Associates the actual page with the view, and drawing it pdfPageView.setPdfPage(pdfPage); diff --git a/examples/components/simpleviewer.js b/examples/components/simpleviewer.js index 5f9da0fcc..c987fd8c9 100644 --- a/examples/components/simpleviewer.js +++ b/examples/components/simpleviewer.js @@ -15,20 +15,20 @@ 'use strict'; -if (!PDFJS.PDFViewer || !PDFJS.getDocument) { +if (!pdfjsDistBuildPdf.getDocument || !pdfjsDistWebPdfViewer.PDFViewer) { alert('Please build the pdfjs-dist library using\n' + ' `gulp dist-install`'); } // The workerSrc property shall be specified. // -PDFJS.GlobalWorkerOptions.workerSrc = +pdfjsDistBuildPdf.GlobalWorkerOptions.workerSrc = '../../node_modules/pdfjs-dist/build/pdf.worker.js'; // Some PDFs need external cmaps. // -// PDFJS.cMapUrl = '../../node_modules/pdfjs-dist/cmaps/'; -// PDFJS.cMapPacked = true; +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'; @@ -36,17 +36,17 @@ var SEARCH_FOR = ''; // try 'Mozilla'; var container = document.getElementById('viewerContainer'); // (Optionally) enable hyperlinks within PDF files. -var pdfLinkService = new PDFJS.PDFLinkService(); +var pdfLinkService = new pdfjsDistWebPdfViewer.PDFLinkService(); -var pdfViewer = new PDFJS.PDFViewer({ +var pdfViewer = new pdfjsDistWebPdfViewer.PDFViewer({ container: container, linkService: pdfLinkService, }); pdfLinkService.setViewer(pdfViewer); // (Optionally) enable find controller. -var pdfFindController = new PDFJS.PDFFindController({ - pdfViewer: pdfViewer +var pdfFindController = new pdfjsDistWebPdfViewer.PDFFindController({ + pdfViewer: pdfViewer, }); pdfViewer.setFindController(pdfFindController); @@ -60,7 +60,11 @@ container.addEventListener('pagesinit', function () { }); // Loading document. -PDFJS.getDocument(DEFAULT_URL).then(function (pdfDocument) { +pdfjsDistBuildPdf.getDocument({ + url: DEFAULT_URL, + cMapUrl: CMAP_URL, + cMapPacked: CMAP_PACKED, +}).then(function(pdfDocument) { // Document loaded, specifying document for the viewer and // the (optional) linkService. pdfViewer.setDocument(pdfDocument); diff --git a/examples/components/singlepageviewer.js b/examples/components/singlepageviewer.js index 90900741e..e1d554e59 100644 --- a/examples/components/singlepageviewer.js +++ b/examples/components/singlepageviewer.js @@ -15,20 +15,20 @@ 'use strict'; -if (!PDFJS.PDFSinglePageViewer || !PDFJS.getDocument) { +if (!pdfjsDistBuildPdf.getDocument || !pdfjsDistWebPdfViewer.PDFSinglePageViewer) { alert('Please build the pdfjs-dist library using\n' + ' `gulp dist-install`'); } // The workerSrc property shall be specified. // -PDFJS.GlobalWorkerOptions.workerSrc = +pdfjsDistBuildPdf.GlobalWorkerOptions.workerSrc = '../../node_modules/pdfjs-dist/build/pdf.worker.js'; // Some PDFs need external cmaps. // -// PDFJS.cMapUrl = '../../node_modules/pdfjs-dist/cmaps/'; -// PDFJS.cMapPacked = true; +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'; @@ -36,17 +36,17 @@ var SEARCH_FOR = ''; // try 'Mozilla'; var container = document.getElementById('viewerContainer'); // (Optionally) enable hyperlinks within PDF files. -var pdfLinkService = new PDFJS.PDFLinkService(); +var pdfLinkService = new pdfjsDistWebPdfViewer.PDFLinkService(); -var pdfSinglePageViewer = new PDFJS.PDFSinglePageViewer({ +var pdfSinglePageViewer = new pdfjsDistWebPdfViewer.PDFSinglePageViewer({ container: container, linkService: pdfLinkService, }); pdfLinkService.setViewer(pdfSinglePageViewer); // (Optionally) enable find controller. -var pdfFindController = new PDFJS.PDFFindController({ - pdfViewer: pdfSinglePageViewer +var pdfFindController = new pdfjsDistWebPdfViewer.PDFFindController({ + pdfViewer: pdfSinglePageViewer, }); pdfSinglePageViewer.setFindController(pdfFindController); @@ -60,7 +60,11 @@ container.addEventListener('pagesinit', function () { }); // Loading document. -PDFJS.getDocument(DEFAULT_URL).then(function (pdfDocument) { +pdfjsDistBuildPdf.getDocument({ + url: DEFAULT_URL, + cMapUrl: CMAP_URL, + cMapPacked: CMAP_PACKED, +}).then(function(pdfDocument) { // Document loaded, specifying document for the viewer and // the (optional) linkService. pdfSinglePageViewer.setDocument(pdfDocument); diff --git a/examples/learning/helloworld.html b/examples/learning/helloworld.html index 5657b73e0..aab3f84b0 100644 --- a/examples/learning/helloworld.html +++ b/examples/learning/helloworld.html @@ -22,13 +22,13 @@ // // The workerSrc property shall be specified. // - PDFJS.GlobalWorkerOptions.workerSrc = + pdfjsDistBuildPdf.GlobalWorkerOptions.workerSrc = '../../node_modules/pdfjs-dist/build/pdf.worker.js'; // // Asynchronous download PDF // - PDFJS.getDocument(url).then(function getPdfHelloWorld(pdf) { + pdfjsDistBuildPdf.getDocument(url).then(function getPdfHelloWorld(pdf) { // // Fetch the first page // diff --git a/examples/learning/helloworld64.html b/examples/learning/helloworld64.html index 263ba905a..e24de3a2e 100644 --- a/examples/learning/helloworld64.html +++ b/examples/learning/helloworld64.html @@ -34,12 +34,12 @@ // // The workerSrc property shall be specified. // - PDFJS.GlobalWorkerOptions.workerSrc = + pdfjsDistBuildPdf.GlobalWorkerOptions.workerSrc = '../../node_modules/pdfjs-dist/build/pdf.worker.js'; // Opening PDF by passing its binary data as a string. It is still preferable // to use Uint8Array, but string or array-like structure will work too. - PDFJS.getDocument({data: pdfData}).then(function getPdfHelloWorld(pdf) { + pdfjsDistBuildPdf.getDocument({data: pdfData}).then(function getPdfHelloWorld(pdf) { // Fetch the first page. pdf.getPage(1).then(function getPageHelloWorld(page) { var scale = 1.5; diff --git a/examples/learning/prevnext.html b/examples/learning/prevnext.html index a315a2118..f02c40dbd 100644 --- a/examples/learning/prevnext.html +++ b/examples/learning/prevnext.html @@ -33,8 +33,8 @@ // pdf.js's one, or the pdf.js is executed via eval(), the workerSrc property // shall be specified. // - // PDFJS.GlobalWorkerOptions.workerSrc = - // '../../node_modules/pdfjs-dist/build/pdf.worker.js'; + pdfjsDistBuildPdf.GlobalWorkerOptions.workerSrc = + '../../node_modules/pdfjs-dist/build/pdf.worker.js'; var pdfDoc = null, pageNum = 1, @@ -117,7 +117,7 @@ /** * Asynchronously downloads PDF. */ - PDFJS.getDocument(url).then(function (pdfDoc_) { + pdfjsDistBuildPdf.getDocument(url).then(function (pdfDoc_) { pdfDoc = pdfDoc_; document.getElementById('page_count').textContent = pdfDoc.numPages; diff --git a/examples/mobile-viewer/viewer.js b/examples/mobile-viewer/viewer.js index 2501dbdfa..7b03cbcb5 100644 --- a/examples/mobile-viewer/viewer.js +++ b/examples/mobile-viewer/viewer.js @@ -12,22 +12,21 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* globals PDFJS */ +/* globals pdfjsDistBuildPdf, pdfjsDistWebPdfViewer */ 'use strict'; -if (typeof PDFJS === 'undefined' || !PDFJS.PDFViewer || !PDFJS.getDocument) { - alert('Please build the pdfjs-dist library using\n' + - ' `gulp dist-install`'); +if (!pdfjsDistBuildPdf.getDocument || !pdfjsDistWebPdfViewer.PDFViewer) { + alert('Please build the pdfjs-dist library using\n `gulp dist-install`'); } var USE_ONLY_CSS_ZOOM = true; var TEXT_LAYER_MODE = 0; // DISABLE -PDFJS.maxImageSize = 1024 * 1024; -PDFJS.cMapUrl = '../../node_modules/pdfjs-dist/cmaps/'; -PDFJS.cMapPacked = true; +var MAX_IMAGE_SIZE = 1024 * 1024; +var CMAP_URL = '../../node_modules/pdfjs-dist/cmaps/'; +var CMAP_PACKED = true; -PDFJS.GlobalWorkerOptions.workerSrc = +pdfjsDistBuildPdf.GlobalWorkerOptions.workerSrc = '../../node_modules/pdfjs-dist/build/pdf.worker.js'; var DEFAULT_URL = '../../web/compressed.tracemonkey-pldi-09.pdf'; @@ -62,7 +61,12 @@ var PDFViewerApplication = { this.setTitleUsingUrl(url); // Loading document. - var loadingTask = PDFJS.getDocument(url); + var loadingTask = pdfjsDistBuildPdf.getDocument({ + url: url, + maxImageSize: MAX_IMAGE_SIZE, + cMapUrl: CMAP_URL, + cMapPacked: CMAP_PACKED, + }); this.pdfLoadingTask = loadingTask; loadingTask.onProgress = function (progressData) { @@ -83,15 +87,15 @@ var PDFViewerApplication = { var l10n = self.l10n; var loadingErrorMessage; - if (exception instanceof PDFJS.InvalidPDFException) { + if (exception instanceof pdfjsDistBuildPdf.InvalidPDFException) { // change error message also for other builds loadingErrorMessage = l10n.get('invalid_file_error', null, 'Invalid or corrupted PDF file.'); - } else if (exception instanceof PDFJS.MissingPDFException) { + } else if (exception instanceof pdfjsDistBuildPdf.MissingPDFException) { // special message for missing PDFs loadingErrorMessage = l10n.get('missing_file_error', null, 'Missing PDF file.'); - } else if (exception instanceof PDFJS.UnexpectedResponseException) { + } else if (exception instanceof pdfjsDistBuildPdf.UnexpectedResponseException) { loadingErrorMessage = l10n.get('unexpected_response_error', null, 'Unexpected server response.'); } else { @@ -133,14 +137,14 @@ var PDFViewerApplication = { }, get loadingBar() { - var bar = new PDFJS.ProgressBar('#loadingBar', {}); + var bar = new pdfjsDistWebPdfViewer.ProgressBar('#loadingBar', {}); - return PDFJS.shadow(this, 'loadingBar', bar); + return pdfjsDistBuildPdf.shadow(this, 'loadingBar', bar); }, setTitleUsingUrl: function pdfViewSetTitleUsingUrl(url) { this.url = url; - var title = PDFJS.getFilenameFromUrl(url) || url; + var title = pdfjsDistBuildPdf.getFilenameFromUrl(url) || url; try { title = decodeURIComponent(title); } catch (e) { @@ -161,8 +165,7 @@ var PDFViewerApplication = { console.log('PDF ' + pdfDocument.fingerprint + ' [' + info.PDFFormatVersion + ' ' + (info.Producer || '-').trim() + ' / ' + (info.Creator || '-').trim() + ']' + - ' (PDF.js: ' + (PDFJS.version || '-') + - (!PDFJS.disableWebGL ? ' [WebGL]' : '') + ')'); + ' (PDF.js: ' + (pdfjsDistBuildPdf.version || '-') + ')'); var pdfTitle; if (metadata && metadata.has('dc:title')) { @@ -192,7 +195,8 @@ var PDFViewerApplication = { error: function pdfViewError(message, moreInfo) { var l10n = this.l10n; var moreInfoText = [l10n.get('error_version_info', - {version: PDFJS.version || '?', build: PDFJS.build || '?'}, + { version: pdfjsDistBuildPdf.version || '?', + build: pdfjsDistBuildPdf.build || '?' }, 'PDF.js v{{version}} (build: {{build}})')]; if (moreInfo) { @@ -290,13 +294,13 @@ var PDFViewerApplication = { }, initUI: function pdfViewInitUI() { - var linkService = new PDFJS.PDFLinkService(); + var linkService = new pdfjsDistWebPdfViewer.PDFLinkService(); this.pdfLinkService = linkService; - this.l10n = PDFJS.NullL10n; + this.l10n = pdfjsDistWebPdfViewer.NullL10n; var container = document.getElementById('viewerContainer'); - var pdfViewer = new PDFJS.PDFViewer({ + var pdfViewer = new pdfjsDistWebPdfViewer.PDFViewer({ container: container, linkService: linkService, l10n: this.l10n, @@ -306,7 +310,7 @@ var PDFViewerApplication = { this.pdfViewer = pdfViewer; linkService.setViewer(pdfViewer); - this.pdfHistory = new PDFJS.PDFHistory({ + this.pdfHistory = new pdfjsDistWebPdfViewer.PDFHistory({ linkService: linkService }); linkService.setHistory(this.pdfHistory); diff --git a/examples/svgviewer/viewer.js b/examples/svgviewer/viewer.js index 04f92f8a2..f29ab7907 100644 --- a/examples/svgviewer/viewer.js +++ b/examples/svgviewer/viewer.js @@ -38,29 +38,31 @@ function renderDocument(pdf, svgLib) { Promise.all([System.import('pdfjs/display/api'), System.import('pdfjs/display/svg'), - System.import('pdfjs/display/global'), System.import('pdfjs/display/worker_options'), System.import('pdfjs/display/network'), System.resolve('pdfjs/worker_loader')]) .then(function (modules) { var api = modules[0]; var svg = modules[1]; - var global = modules[2]; - var GlobalWorkerOptions = modules[3].GlobalWorkerOptions; - var network = modules[4]; + var GlobalWorkerOptions = modules[2].GlobalWorkerOptions; + var network = modules[3]; api.setPDFNetworkStreamFactory((params) => { return new network.PDFNetworkStream(params); }); // In production, change this to point to the built `pdf.worker.js` file. - GlobalWorkerOptions.workerSrc = modules[5]; + GlobalWorkerOptions.workerSrc = modules[4]; // In production, change this to point to where the cMaps are placed. - global.PDFJS.cMapUrl = '../../external/bcmaps/'; - global.PDFJS.cMapPacked = true; + var CMAP_URL = '../../external/bcmaps/'; + var CMAP_PACKED = true; // Fetch the PDF document from the URL using promises. - api.getDocument(url).then(function (doc) { + api.getDocument({ + url: url, + cMapUrl: CMAP_URL, + cMapPacked: CMAP_PACKED, + }).then(function(doc) { renderDocument(doc, svg); }); }); diff --git a/examples/text-only/pdf2svg.js b/examples/text-only/pdf2svg.js index eeb53bfb6..328121a54 100644 --- a/examples/text-only/pdf2svg.js +++ b/examples/text-only/pdf2svg.js @@ -18,7 +18,7 @@ var PAGE_NUMBER = 1; var PAGE_SCALE = 1.5; var SVG_NS = 'http://www.w3.org/2000/svg'; -PDFJS.GlobalWorkerOptions.workerSrc = +pdfjsDistBuildPdf.GlobalWorkerOptions.workerSrc = '../../node_modules/pdfjs-dist/build/pdf.worker.js'; function buildSVG(viewport, textContent) { @@ -33,8 +33,8 @@ function buildSVG(viewport, textContent) { 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 = PDFJS.Util.transform( - PDFJS.Util.transform(viewport.transform, textItem.transform), + var tx = pdfjsDistBuildPdf.Util.transform( + pdfjsDistBuildPdf.Util.transform(viewport.transform, textItem.transform), [1, 0, 0, -1, 0, 0]); var style = textContent.styles[textItem.fontName]; // adding text element @@ -49,7 +49,7 @@ function buildSVG(viewport, textContent) { function pageLoaded() { // Loading document and page text content - PDFJS.getDocument({url: PDF_PATH}).then(function (pdfDocument) { + pdfjsDistBuildPdf.getDocument({url: PDF_PATH}).then(function (pdfDocument) { pdfDocument.getPage(PAGE_NUMBER).then(function (page) { var viewport = page.getViewport(PAGE_SCALE); page.getTextContent().then(function (textContent) { @@ -62,7 +62,7 @@ function pageLoaded() { } document.addEventListener('DOMContentLoaded', function () { - if (typeof PDFJS === 'undefined') { + if (typeof pdfjsDistBuildPdf === 'undefined') { alert('Built version of PDF.js was not found.\n' + 'Please run `gulp dist-install`.'); return; diff --git a/gulpfile.js b/gulpfile.js index 3568da316..54ef27640 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -934,7 +934,6 @@ gulp.task('jsdoc', function (done) { var JSDOC_FILES = [ 'src/doc_helper.js', 'src/display/api.js', - 'src/display/global.js', 'src/shared/util.js', 'src/core/annotation.js' ]; diff --git a/src/core/worker.js b/src/core/worker.js index 12a75df53..742718aad 100644 --- a/src/core/worker.js +++ b/src/core/worker.js @@ -614,7 +614,7 @@ var WorkerMessageHandler = { var evaluatorOptions = { forceDataSchema: data.disableCreateObjectURL, - maxImageSize: data.maxImageSize === undefined ? -1 : data.maxImageSize, + maxImageSize: data.maxImageSize, disableFontFace: data.disableFontFace, nativeImageDecoderSupport: data.nativeImageDecoderSupport, ignoreErrors: data.ignoreErrors, diff --git a/src/display/api.js b/src/display/api.js index bdec3bf94..163f257b2 100644 --- a/src/display/api.js +++ b/src/display/api.js @@ -18,14 +18,15 @@ import { assert, createPromiseCapability, getVerbosityLevel, info, InvalidPDFException, isArrayBuffer, isNum, isSameOrigin, MessageHandler, MissingPDFException, NativeImageDecoding, PageViewport, PasswordException, setVerbosityLevel, - stringToBytes, UnexpectedResponseException, UnknownErrorException, + shadow, stringToBytes, UnexpectedResponseException, UnknownErrorException, unreachable, Util, warn } from '../shared/util'; import { - DOMCanvasFactory, DOMCMapReaderFactory, DummyStatTimer, getDefaultSetting, + DOMCanvasFactory, DOMCMapReaderFactory, DummyStatTimer, RenderingCancelledException, StatTimer } from './dom_utils'; import { FontFaceObject, FontLoader } from './font_loader'; +import { apiCompatibilityParams } from './api_compatibility'; import { CanvasGraphics } from './canvas'; import globalScope from '../shared/global_scope'; import { GlobalWorkerOptions } from './worker_options'; @@ -142,6 +143,10 @@ function setPDFNetworkStreamFactory(pdfNetworkStreamFactory) { * with limited image support through stubs (useful for SVG conversion), * and 'none' where JPEG images will be decoded entirely by PDF.js. * The default value is 'decode'. + * @property {string} cMapUrl - (optional) The URL where the predefined + * Adobe CMaps are located. Include trailing slash. + * @property {boolean} cMapPacked - (optional) Specifies if the Adobe CMaps are + * binary packed. * @property {Object} CMapReaderFactory - (optional) The factory that will be * used when reading built-in CMap files. Providing a custom factory is useful * for environments without `XMLHttpRequest` support, such as e.g. Node.js. @@ -150,6 +155,34 @@ function setPDFNetworkStreamFactory(pdfNetworkStreamFactory) { * `getOperatorList`, `getTextContent`, and `RenderTask`, when the associated * PDF data cannot be successfully parsed, instead of attempting to recover * whatever possible of the data. The default value is `false`. + * @property {number} maxImageSize - (optional) The maximum allowed image size + * in total pixels, i.e. width * height. Images above this value will not be + * rendered. Use -1 for no limit, which is also the default value. + * @property {boolean} isEvalSupported - (optional) Determines if we can eval + * strings as JS. Primarily used to improve performance of font rendering, + * and when parsing PDF functions. The default value is `true`. + * @property {boolean} disableFontFace - (optional) By default fonts are + * converted to OpenType fonts and loaded via font face rules. If disabled, + * fonts will be rendered using a built-in font renderer that constructs the + * glyphs with primitive path commands. The default value is `false`. + * @property {boolean} disableRange - (optional) Disable range request loading + * of PDF files. When enabled, and if the server supports partial content + * requests, then the PDF will be fetched in chunks. + * The default value is `false`. + * @property {boolean} disableStream - (optional) Disable streaming of PDF file + * data. By default PDF.js attempts to load PDFs in chunks. + * The default value is `false`. + * @property {boolean} disableAutoFetch - (optional) Disable pre-fetching of PDF + * file data. When range requests are enabled PDF.js will automatically keep + * fetching more data even if it isn't needed to display the current page. + * The default value is `false`. + * NOTE: It is also necessary to disable streaming, see above, + * in order for disabling of pre-fetching to work correctly. + * @property {boolean} disableCreateObjectURL - (optional) Disable the use of + * `URL.createObjectURL`, for compatibility with older browsers. + * The default value is `false`. + * @property {boolean} pdfBug - (optional) Enables special hooks for debugging + * PDF.js (see `web/debugger.js`). The default value is `false`. */ /** @@ -195,10 +228,10 @@ function getDocument(src) { source = src; } - var params = {}; + let params = Object.create(null); var rangeTransport = null; let worker = null; - var CMapReaderFactory = DOMCMapReaderFactory; + let CMapReaderFactory = DOMCMapReaderFactory; for (var key in source) { if (key === 'url' && typeof window !== 'undefined') { @@ -236,12 +269,36 @@ function getDocument(src) { params.rangeChunkSize = params.rangeChunkSize || DEFAULT_RANGE_CHUNK_SIZE; params.ignoreErrors = params.stopAtErrors !== true; + params.pdfBug = params.pdfBug === true; - const nativeImageDecoderValues = Object.values(NativeImageDecoding); + const NativeImageDecoderValues = Object.values(NativeImageDecoding); if (params.nativeImageDecoderSupport === undefined || - !nativeImageDecoderValues.includes(params.nativeImageDecoderSupport)) { + !NativeImageDecoderValues.includes(params.nativeImageDecoderSupport)) { params.nativeImageDecoderSupport = NativeImageDecoding.DECODE; } + if (!Number.isInteger(params.maxImageSize)) { + params.maxImageSize = -1; + } + if (typeof params.isEvalSupported !== 'boolean') { + params.isEvalSupported = true; + } + if (typeof params.disableFontFace !== 'boolean') { + params.disableFontFace = false; + } + + if (typeof params.disableRange !== 'boolean') { + params.disableRange = apiCompatibilityParams.disableRange || false; + } + if (typeof params.disableStream !== 'boolean') { + params.disableStream = apiCompatibilityParams.disableStream || false; + } + if (typeof params.disableAutoFetch !== 'boolean') { + params.disableAutoFetch = false; + } + if (typeof params.disableCreateObjectURL !== 'boolean') { + params.disableCreateObjectURL = + apiCompatibilityParams.disableCreateObjectURL || false; + } // Set the main-thread verbosity level. setVerbosityLevel(params.verbosity); @@ -275,15 +332,28 @@ function getDocument(src) { let networkStream; if (rangeTransport) { - networkStream = new PDFDataTransportStream(params, rangeTransport); + networkStream = new PDFDataTransportStream({ + length: params.length, + initialData: params.initialData, + disableRange: params.disableRange, + disableStream: params.disableStream, + }, rangeTransport); } else if (!params.data) { - networkStream = createPDFNetworkStream(params); + networkStream = createPDFNetworkStream({ + url: params.url, + length: params.length, + httpHeaders: params.httpHeaders, + withCredentials: params.withCredentials, + rangeChunkSize: params.rangeChunkSize, + disableRange: params.disableRange, + disableStream: params.disableStream, + }); } var messageHandler = new MessageHandler(docId, workerId, worker.port); messageHandler.postMessageTransfers = worker.postMessageTransfers; var transport = new WorkerTransport(messageHandler, task, networkStream, - CMapReaderFactory); + params, CMapReaderFactory); task._transport = transport; messageHandler.send('Ready', null); }); @@ -306,19 +376,15 @@ function _fetchDocument(worker, source, pdfDataRangeTransport, docId) { if (worker.destroyed) { return Promise.reject(new Error('Worker was destroyed')); } - let apiVersion = - typeof PDFJSDev !== 'undefined' ? PDFJSDev.eval('BUNDLE_VERSION') : null; - source.disableRange = getDefaultSetting('disableRange'); - source.disableAutoFetch = getDefaultSetting('disableAutoFetch'); - source.disableStream = getDefaultSetting('disableStream'); if (pdfDataRangeTransport) { source.length = pdfDataRangeTransport.length; source.initialData = pdfDataRangeTransport.initialData; } return worker.messageHandler.sendWithPromise('GetDocRequest', { docId, - apiVersion, + apiVersion: (typeof PDFJSDev !== 'undefined' ? + PDFJSDev.eval('BUNDLE_VERSION') : null), source: { data: source.data, url: source.url, @@ -327,14 +393,14 @@ function _fetchDocument(worker, source, pdfDataRangeTransport, docId) { rangeChunkSize: source.rangeChunkSize, length: source.length, }, - maxImageSize: getDefaultSetting('maxImageSize'), - disableFontFace: getDefaultSetting('disableFontFace'), - disableCreateObjectURL: getDefaultSetting('disableCreateObjectURL'), + maxImageSize: source.maxImageSize, + disableFontFace: source.disableFontFace, + disableCreateObjectURL: source.disableCreateObjectURL, postMessageTransfers: worker.postMessageTransfers, docBaseUrl: source.docBaseUrl, nativeImageDecoderSupport: source.nativeImageDecoderSupport, ignoreErrors: source.ignoreErrors, - isEvalSupported: getDefaultSetting('isEvalSupported'), + isEvalSupported: source.isEvalSupported, }).then(function (workerId) { if (worker.destroyed) { throw new Error('Worker was destroyed'); @@ -660,6 +726,10 @@ var PDFDocumentProxy = (function PDFDocumentProxyClosure() { destroy: function PDFDocumentProxy_destroy() { return this.loadingTask.destroy(); }, + + get loadingParams() { + return this.transport.loadingParams; + }, }; return PDFDocumentProxy; })(); @@ -757,12 +827,12 @@ var PDFDocumentProxy = (function PDFDocumentProxyClosure() { * @alias PDFPageProxy */ var PDFPageProxy = (function PDFPageProxyClosure() { - function PDFPageProxy(pageIndex, pageInfo, transport) { + function PDFPageProxy(pageIndex, pageInfo, transport, pdfBug = false) { this.pageIndex = pageIndex; this.pageInfo = pageInfo; this.transport = transport; - this._stats = (getDefaultSetting('pdfBug') ? - new StatTimer() : DummyStatTimer); + this._stats = (pdfBug ? new StatTimer() : DummyStatTimer); + this._pdfBug = pdfBug; this.commonObjs = transport.commonObjs; this.objs = new PDFObjects(); this.cleanupAfterRender = false; @@ -899,7 +969,8 @@ var PDFPageProxy = (function PDFPageProxyClosure() { intentState.operatorList, this.pageNumber, canvasFactory, - webGLContext); + webGLContext, + this._pdfBug); internalRenderTask.useRequestAnimationFrame = renderingIntent !== 'print'; if (!intentState.renderTasks) { intentState.renderTasks = []; @@ -1544,14 +1615,15 @@ var PDFWorker = (function PDFWorkerClosure() { */ var WorkerTransport = (function WorkerTransportClosure() { function WorkerTransport(messageHandler, loadingTask, networkStream, - CMapReaderFactory) { + params, CMapReaderFactory) { this.messageHandler = messageHandler; this.loadingTask = loadingTask; this.commonObjs = new PDFObjects(); this.fontLoader = new FontLoader(loadingTask.docId); + this._params = params; this.CMapReaderFactory = new CMapReaderFactory({ - baseUrl: getDefaultSetting('cMapUrl'), - isCompressed: getDefaultSetting('cMapPacked'), + baseUrl: params.cMapUrl, + isCompressed: params.cMapPacked, }); this.destroyed = false; @@ -1795,6 +1867,7 @@ var WorkerTransport = (function WorkerTransportClosure() { switch (type) { case 'Font': var exportedData = data[2]; + let params = this._params; if ('error' in exportedData) { var exportedError = exportedData.error; @@ -1803,8 +1876,8 @@ var WorkerTransport = (function WorkerTransportClosure() { break; } var fontRegistry = null; - if (getDefaultSetting('pdfBug') && globalScope.FontInspector && - globalScope['FontInspector'].enabled) { + if (params.pdfBug && globalScope.FontInspector && + globalScope.FontInspector.enabled) { fontRegistry = { registerFont(font, url) { globalScope['FontInspector'].fontAdded(font, url); @@ -1812,8 +1885,8 @@ var WorkerTransport = (function WorkerTransportClosure() { }; } var font = new FontFaceObject(exportedData, { - isEvalSupported: getDefaultSetting('isEvalSupported'), - disableFontFace: getDefaultSetting('disableFontFace'), + isEvalSupported: params.isEvalSupported, + disableFontFace: params.disableFontFace, fontRegistry, }); var fontReady = (fontObjs) => { @@ -2010,7 +2083,8 @@ var WorkerTransport = (function WorkerTransportClosure() { if (this.destroyed) { throw new Error('Transport destroyed'); } - var page = new PDFPageProxy(pageIndex, pageInfo, this); + let page = new PDFPageProxy(pageIndex, pageInfo, this, + this._params.pdfBug); this.pageCache[pageIndex] = page; return page; }); @@ -2091,6 +2165,16 @@ var WorkerTransport = (function WorkerTransportClosure() { this.fontLoader.clear(); }); }, + + get loadingParams() { + let params = this._params; + return shadow(this, 'loadingParams', { + disableRange: params.disableRange, + disableStream: params.disableStream, + disableAutoFetch: params.disableAutoFetch, + disableCreateObjectURL: params.disableCreateObjectURL, + }); + }, }; return WorkerTransport; @@ -2260,7 +2344,8 @@ var InternalRenderTask = (function InternalRenderTaskClosure() { let canvasInRendering = new WeakMap(); function InternalRenderTask(callback, params, objs, commonObjs, operatorList, - pageNumber, canvasFactory, webGLContext) { + pageNumber, canvasFactory, webGLContext, + pdfBug = false) { this.callback = callback; this.params = params; this.objs = objs; @@ -2270,6 +2355,7 @@ var InternalRenderTask = (function InternalRenderTaskClosure() { this.pageNumber = pageNumber; this.canvasFactory = canvasFactory; this.webGLContext = webGLContext; + this._pdfBug = pdfBug; this.running = false; this.graphicsReadyCallback = null; @@ -2303,7 +2389,7 @@ var InternalRenderTask = (function InternalRenderTaskClosure() { if (this.cancelled) { return; } - if (getDefaultSetting('pdfBug') && globalScope.StepperManager && + if (this._pdfBug && globalScope.StepperManager && globalScope.StepperManager.enabled) { this.stepper = globalScope.StepperManager.create(this.pageNumber - 1); this.stepper.init(this.operatorList); diff --git a/src/display/api_compatibility.js b/src/display/api_compatibility.js new file mode 100644 index 000000000..09e283e75 --- /dev/null +++ b/src/display/api_compatibility.js @@ -0,0 +1,50 @@ +/* Copyright 2018 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +let compatibilityParams = Object.create(null); +if (typeof PDFJSDev === 'undefined' || PDFJSDev.test('GENERIC')) { + const userAgent = + (typeof navigator !== 'undefined' && navigator.userAgent) || ''; + const isIE = /Trident/.test(userAgent); + const isIOS = /\b(iPad|iPhone|iPod)(?=;)/.test(userAgent); + const isIOSChrome = /CriOS/.test(userAgent); + const isSafari = /Safari\//.test(userAgent) && + !/(Chrome\/|Android\s)/.test(userAgent); + + // Checks if possible to use URL.createObjectURL() + // Support: IE, Chrome on iOS + (function checkOnBlobSupport() { + // Sometimes IE and Chrome on iOS losing the data created with + // createObjectURL(), see issues #3977 and #8081. + if (isIE || isIOSChrome) { + compatibilityParams.disableCreateObjectURL = true; + } + })(); + + // Support: Safari 6.0+, iOS + (function checkRangeRequests() { + // Safari has issues with cached range requests, see issue #3260. + // Last tested with version 6.0.4. + if (isSafari || isIOS) { + compatibilityParams.disableRange = true; + compatibilityParams.disableStream = true; + } + })(); +} +const apiCompatibilityParams = Object.freeze(compatibilityParams); + +export { + apiCompatibilityParams, +}; diff --git a/src/display/dom_utils.js b/src/display/dom_utils.js index 69a9e974c..565c9836a 100644 --- a/src/display/dom_utils.js +++ b/src/display/dom_utils.js @@ -17,7 +17,6 @@ import { assert, CMapCompressionType, removeNullCharacters, stringToBytes, unreachable, warn } from '../shared/util'; -import globalScope from '../shared/global_scope'; const DEFAULT_LINK_REL = 'noopener noreferrer nofollow'; const SVG_NS = 'http://www.w3.org/2000/svg'; @@ -69,8 +68,9 @@ class DOMCMapReaderFactory { fetch({ name, }) { if (!this.baseUrl) { - return Promise.reject(new Error('CMap baseUrl must be specified, ' + - 'see "PDFJS.cMapUrl" (and also "PDFJS.cMapPacked").')); + return Promise.reject(new Error( + 'The CMap "baseUrl" parameter must be specified, ensure that ' + + 'the "cMapUrl" and "cMapPacked" API parameters are provided.')); } if (!name) { return Promise.reject(new Error('CMap name must be specified.')); @@ -328,36 +328,6 @@ function getFilenameFromUrl(url) { return url.substring(url.lastIndexOf('/', end) + 1, end); } -function getDefaultSetting(id) { - // The list of the settings and their default is maintained for backward - // compatibility and shall not be extended or modified. See also global.js. - var globalSettings = globalScope.PDFJS; - switch (id) { - case 'pdfBug': - return globalSettings ? globalSettings.pdfBug : false; - case 'disableAutoFetch': - return globalSettings ? globalSettings.disableAutoFetch : false; - case 'disableStream': - return globalSettings ? globalSettings.disableStream : false; - case 'disableRange': - return globalSettings ? globalSettings.disableRange : false; - case 'disableFontFace': - return globalSettings ? globalSettings.disableFontFace : false; - case 'disableCreateObjectURL': - return globalSettings ? globalSettings.disableCreateObjectURL : false; - case 'cMapUrl': - return globalSettings ? globalSettings.cMapUrl : null; - case 'cMapPacked': - return globalSettings ? globalSettings.cMapPacked : false; - case 'maxImageSize': - return globalSettings ? globalSettings.maxImageSize : -1; - case 'isEvalSupported': - return globalSettings ? globalSettings.isEvalSupported : true; - default: - throw new Error('Unknown default setting: ' + id); - } -} - class StatTimer { constructor(enable = true) { this.enabled = !!enable; @@ -437,7 +407,6 @@ export { addLinkAttributes, getFilenameFromUrl, LinkTarget, - getDefaultSetting, DEFAULT_LINK_REL, DOMCanvasFactory, DOMCMapReaderFactory, diff --git a/src/display/font_loader.js b/src/display/font_loader.js index 7e8ffcdd2..904712bf6 100644 --- a/src/display/font_loader.js +++ b/src/display/font_loader.js @@ -336,13 +336,17 @@ var IsEvalSupportedCached = { }; var FontFaceObject = (function FontFaceObjectClosure() { - function FontFaceObject(translatedData, options) { + function FontFaceObject(translatedData, { isEvalSupported = true, + disableFontFace = false, + fontRegistry = null, }) { this.compiledGlyphs = Object.create(null); // importing translated data for (var i in translatedData) { this[i] = translatedData[i]; } - this.options = options; + this.isEvalSupported = isEvalSupported !== false; + this.disableFontFace = disableFontFace === true; + this.fontRegistry = fontRegistry; } FontFaceObject.prototype = { createNativeFontFace: function FontFaceObject_createNativeFontFace() { @@ -350,30 +354,20 @@ var FontFaceObject = (function FontFaceObjectClosure() { throw new Error('Not implemented: createNativeFontFace'); } - if (!this.data) { - return null; - } - - if (this.options.disableFontFace) { - this.disableFontFace = true; + if (!this.data || this.disableFontFace) { return null; } var nativeFontFace = new FontFace(this.loadedName, this.data, {}); - if (this.options.fontRegistry) { - this.options.fontRegistry.registerFont(this); + if (this.fontRegistry) { + this.fontRegistry.registerFont(this); } return nativeFontFace; }, createFontFaceRule: function FontFaceObject_createFontFaceRule() { - if (!this.data) { - return null; - } - - if (this.options.disableFontFace) { - this.disableFontFace = true; + if (!this.data || this.disableFontFace) { return null; } @@ -384,8 +378,8 @@ var FontFaceObject = (function FontFaceObjectClosure() { var url = ('url(data:' + this.mimetype + ';base64,' + btoa(data) + ');'); var rule = '@font-face { font-family:"' + fontName + '";src:' + url + '}'; - if (this.options.fontRegistry) { - this.options.fontRegistry.registerFont(this, url); + if (this.fontRegistry) { + this.fontRegistry.registerFont(this, url); } return rule; @@ -398,7 +392,7 @@ var FontFaceObject = (function FontFaceObjectClosure() { var current, i, len; // If we can, compile cmds into JS for MAXIMUM SPEED - if (this.options.isEvalSupported && IsEvalSupportedCached.value) { + if (this.isEvalSupported && IsEvalSupportedCached.value) { var args, js = ''; for (i = 0, len = cmds.length; i < len; i++) { current = cmds[i]; diff --git a/src/display/global.js b/src/display/global.js deleted file mode 100644 index c4b329fdc..000000000 --- a/src/display/global.js +++ /dev/null @@ -1,188 +0,0 @@ -/* Copyright 2015 Mozilla Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { - createBlob, createObjectURL, createPromiseCapability, InvalidPDFException, - isLittleEndian, MissingPDFException, OPS, PageViewport, PasswordException, - PasswordResponses, removeNullCharacters, shadow, UnexpectedResponseException, - UnknownErrorException, UNSUPPORTED_FEATURES, Util -} from '../shared/util'; -import { DEFAULT_LINK_REL, getFilenameFromUrl, LinkTarget } from './dom_utils'; -import { - getDocument, LoopbackPort, PDFDataRangeTransport, PDFWorker -} from './api'; -import { AnnotationLayer } from './annotation_layer'; -import globalScope from '../shared/global_scope'; -import { GlobalWorkerOptions } from './worker_options'; -import { Metadata } from './metadata'; -import { renderTextLayer } from './text_layer'; -import { SVGGraphics } from './svg'; - -// The global PDFJS object is now deprecated and will not be supported in -// the future. The members below are maintained for backward compatibility -// and shall not be extended or modified. If the global.js is included as -// a module, we will create a global PDFJS object instance or use existing. -if (!globalScope.PDFJS) { - globalScope.PDFJS = {}; -} -var PDFJS = globalScope.PDFJS; - -PDFJS.pdfBug = false; - -PDFJS.OPS = OPS; -PDFJS.UNSUPPORTED_FEATURES = UNSUPPORTED_FEATURES; -PDFJS.shadow = shadow; -PDFJS.createBlob = createBlob; -PDFJS.createObjectURL = function PDFJS_createObjectURL(data, contentType) { - return createObjectURL(data, contentType, PDFJS.disableCreateObjectURL); -}; -Object.defineProperty(PDFJS, 'isLittleEndian', { - configurable: true, - get: function PDFJS_isLittleEndian() { - return shadow(PDFJS, 'isLittleEndian', isLittleEndian()); - }, -}); -PDFJS.removeNullCharacters = removeNullCharacters; -PDFJS.PasswordResponses = PasswordResponses; -PDFJS.PasswordException = PasswordException; -PDFJS.UnknownErrorException = UnknownErrorException; -PDFJS.InvalidPDFException = InvalidPDFException; -PDFJS.MissingPDFException = MissingPDFException; -PDFJS.UnexpectedResponseException = UnexpectedResponseException; -PDFJS.Util = Util; -PDFJS.PageViewport = PageViewport; -PDFJS.createPromiseCapability = createPromiseCapability; - -/** - * The maximum allowed image size in total pixels e.g. width * height. Images - * above this value will not be drawn. Use -1 for no limit. - * @var {number} - */ -PDFJS.maxImageSize = (PDFJS.maxImageSize === undefined ? - -1 : PDFJS.maxImageSize); - -/** - * The url of where the predefined Adobe CMaps are located. Include trailing - * slash. - * @var {string} - */ -PDFJS.cMapUrl = (PDFJS.cMapUrl === undefined ? null : PDFJS.cMapUrl); - -/** - * Specifies if CMaps are binary packed. - * @var {boolean} - */ -PDFJS.cMapPacked = PDFJS.cMapPacked === undefined ? false : PDFJS.cMapPacked; - -/** - * By default fonts are converted to OpenType fonts and loaded via font face - * rules. If disabled, the font will be rendered using a built in font - * renderer that constructs the glyphs with primitive path commands. - * @var {boolean} - */ -PDFJS.disableFontFace = (PDFJS.disableFontFace === undefined ? - false : PDFJS.disableFontFace); - -/** - * Disable range request loading of PDF files. When enabled and if the server - * supports partial content requests then the PDF will be fetched in chunks. - * Enabled (false) by default. - * @var {boolean} - */ -PDFJS.disableRange = (PDFJS.disableRange === undefined ? - false : PDFJS.disableRange); - -/** - * Disable streaming of PDF file data. By default PDF.js attempts to load PDF - * in chunks. This default behavior can be disabled. - * @var {boolean} - */ -PDFJS.disableStream = (PDFJS.disableStream === undefined ? - false : PDFJS.disableStream); - -/** - * Disable pre-fetching of PDF file data. When range requests are enabled - * PDF.js will automatically keep fetching more data even if it isn't needed - * to display the current page. This default behavior can be disabled. - * - * NOTE: It is also necessary to disable streaming, see above, - * in order for disabling of pre-fetching to work correctly. - * @var {boolean} - */ -PDFJS.disableAutoFetch = (PDFJS.disableAutoFetch === undefined ? - false : PDFJS.disableAutoFetch); - -/** - * Enables special hooks for debugging PDF.js. - * @var {boolean} - */ -PDFJS.pdfBug = (PDFJS.pdfBug === undefined ? false : PDFJS.pdfBug); - -/** - * Disables URL.createObjectURL usage. - * @var {boolean} - */ -PDFJS.disableCreateObjectURL = (PDFJS.disableCreateObjectURL === undefined ? - false : PDFJS.disableCreateObjectURL); - -/** - * Specifies the |target| attribute for external links. - * The constants from {LinkTarget} should be used: - * - NONE [default] - * - SELF - * - BLANK - * - PARENT - * - TOP - * @var {number} - */ -PDFJS.externalLinkTarget = (PDFJS.externalLinkTarget === undefined ? - LinkTarget.NONE : PDFJS.externalLinkTarget); - -/** - * Specifies the |rel| attribute for external links. Defaults to stripping - * the referrer. - * @var {string} - */ -PDFJS.externalLinkRel = (PDFJS.externalLinkRel === undefined ? - DEFAULT_LINK_REL : PDFJS.externalLinkRel); - -/** - * Determines if we can eval strings as JS. Primarily used to improve - * performance for font rendering. - * @var {boolean} - */ -PDFJS.isEvalSupported = (PDFJS.isEvalSupported === undefined ? - true : PDFJS.isEvalSupported); - -PDFJS.getDocument = getDocument; -PDFJS.LoopbackPort = LoopbackPort; -PDFJS.PDFDataRangeTransport = PDFDataRangeTransport; -PDFJS.PDFWorker = PDFWorker; -PDFJS.GlobalWorkerOptions = GlobalWorkerOptions; - -PDFJS.getFilenameFromUrl = getFilenameFromUrl; - -PDFJS.AnnotationLayer = AnnotationLayer; - -PDFJS.renderTextLayer = renderTextLayer; - -PDFJS.Metadata = Metadata; - -PDFJS.SVGGraphics = SVGGraphics; - -export { - globalScope, - PDFJS, -}; diff --git a/src/display/text_layer.js b/src/display/text_layer.js index 4362fa7b4..3bf75f584 100644 --- a/src/display/text_layer.js +++ b/src/display/text_layer.js @@ -14,7 +14,7 @@ */ import { AbortException, createPromiseCapability, Util } from '../shared/util'; -import { getDefaultSetting } from './dom_utils'; +import globalScope from '../shared/global_scope'; /** * Text layer render parameters. @@ -107,11 +107,9 @@ var renderTextLayer = (function renderTextLayerClosure() { textDiv.setAttribute('style', textDivProperties.style); textDiv.textContent = geom.str; - // |fontName| is only used by the Font Inspector. This test will succeed - // when e.g. the Font Inspector is off but the Stepper is on, but it's - // not worth the effort to do a more accurate test. We only use `dataset` - // here to make the font name available for the debugger. - if (getDefaultSetting('pdfBug')) { + // `fontName` is only used by the FontInspector, and we only use `dataset` + // here to make the font name available in the debugger. + if (task._fontInspectorEnabled) { textDiv.dataset.fontName = geom.fontName; } if (angle !== 0) { @@ -479,6 +477,8 @@ var renderTextLayer = (function renderTextLayerClosure() { this._textDivs = textDivs || []; this._textContentItemsStr = textContentItemsStr || []; this._enhanceTextSelection = !!enhanceTextSelection; + this._fontInspectorEnabled = !!(globalScope.FontInspector && + globalScope.FontInspector.enabled); this._reader = null; this._layoutTextLastFontSize = null; diff --git a/src/doc_helper.js b/src/doc_helper.js index 69b055144..fd640b786 100644 --- a/src/doc_helper.js +++ b/src/doc_helper.js @@ -18,15 +18,6 @@ It is not for use in the executable code. */ -/** - * PDFJS scope object that contains all functions, objects and variables related - * to the PDF.js. - * @constructor - */ -function PDFJS() { // eslint-disable-line no-unused-vars - // Mock class constructor. See src/display/api.js. -} - /** * Represents the eventual result of an asynchronous operation. * @external Promise diff --git a/src/pdf.js b/src/pdf.js index 48657fb95..ea3a3cd83 100644 --- a/src/pdf.js +++ b/src/pdf.js @@ -22,13 +22,13 @@ var pdfjsBuild = typeof PDFJSDev !== 'undefined' ? PDFJSDev.eval('BUNDLE_BUILD') : void 0; var pdfjsSharedUtil = require('./shared/util.js'); -var pdfjsDisplayGlobal = require('./display/global.js'); var pdfjsDisplayAPI = require('./display/api.js'); var pdfjsDisplayTextLayer = require('./display/text_layer.js'); var pdfjsDisplayAnnotationLayer = require('./display/annotation_layer.js'); var pdfjsDisplayDOMUtils = require('./display/dom_utils.js'); var pdfjsDisplaySVG = require('./display/svg.js'); let pdfjsDisplayWorkerOptions = require('./display/worker_options.js'); +let pdfjsDisplayAPICompatibility = require('./display/api_compatibility.js'); if (typeof PDFJSDev === 'undefined' || PDFJSDev.test('GENERIC')) { const isNodeJS = require('./shared/is_node.js'); @@ -65,7 +65,6 @@ if (typeof PDFJSDev === 'undefined' || PDFJSDev.test('GENERIC')) { }); } -exports.PDFJS = pdfjsDisplayGlobal.PDFJS; exports.build = pdfjsDisplayAPI.build; exports.version = pdfjsDisplayAPI.version; exports.getDocument = pdfjsDisplayAPI.getDocument; @@ -90,9 +89,12 @@ exports.createObjectURL = pdfjsSharedUtil.createObjectURL; exports.removeNullCharacters = pdfjsSharedUtil.removeNullCharacters; exports.shadow = pdfjsSharedUtil.shadow; exports.createBlob = pdfjsSharedUtil.createBlob; +exports.Util = pdfjsSharedUtil.Util; exports.RenderingCancelledException = pdfjsDisplayDOMUtils.RenderingCancelledException; exports.getFilenameFromUrl = pdfjsDisplayDOMUtils.getFilenameFromUrl; exports.LinkTarget = pdfjsDisplayDOMUtils.LinkTarget; exports.addLinkAttributes = pdfjsDisplayDOMUtils.addLinkAttributes; exports.GlobalWorkerOptions = pdfjsDisplayWorkerOptions.GlobalWorkerOptions; +exports.apiCompatibilityParams = + pdfjsDisplayAPICompatibility.apiCompatibilityParams; diff --git a/src/shared/compatibility.js b/src/shared/compatibility.js index 10f91958f..5a4911357 100644 --- a/src/shared/compatibility.js +++ b/src/shared/compatibility.js @@ -13,38 +13,25 @@ * limitations under the License. */ /* eslint-disable mozilla/use-includes-instead-of-indexOf */ -/* globals PDFJS */ + +const globalScope = require('./global_scope'); // Skip compatibility checks for the extensions and if we already ran // this module. if ((typeof PDFJSDev === 'undefined' || !PDFJSDev.test('FIREFOX || MOZCENTRAL')) && - (typeof PDFJS === 'undefined' || !PDFJS.compatibilityChecked)) { + !globalScope._pdfjsCompatibilityChecked) { + +globalScope._pdfjsCompatibilityChecked = true; // In the Chrome extension, most of the polyfills are unnecessary. // We support down to Chrome 49, because it's still commonly used by Windows XP // users - https://github.com/mozilla/pdf.js/issues/9397 if (typeof PDFJSDev === 'undefined' || !PDFJSDev.test('CHROME')) { -const globalScope = require('./global_scope'); const isNodeJS = require('./is_node'); -var userAgent = (typeof navigator !== 'undefined' && navigator.userAgent) || ''; -var isIOSChrome = userAgent.indexOf('CriOS') >= 0; -var isIE = userAgent.indexOf('Trident') >= 0; -var isIOS = /\b(iPad|iPhone|iPod)(?=;)/.test(userAgent); -var isSafari = /Safari\//.test(userAgent) && - !/(Chrome\/|Android\s)/.test(userAgent); - -var hasDOM = typeof window === 'object' && typeof document === 'object'; - -// Initializing PDFJS global object here, it case if we need to change/disable -// some PDF.js features, e.g. range requests -if (typeof PDFJS === 'undefined') { - globalScope.PDFJS = {}; -} - -PDFJS.compatibilityChecked = true; +const hasDOM = typeof window === 'object' && typeof document === 'object'; // Support: Node.js (function checkNodeBtoa() { @@ -68,27 +55,6 @@ PDFJS.compatibilityChecked = true; }; })(); -// Checks if possible to use URL.createObjectURL() -// Support: IE, Chrome on iOS -(function checkOnBlobSupport() { - // sometimes IE and Chrome on iOS loosing the data created with - // createObjectURL(), see #3977 and #8081 - if (isIE || isIOSChrome) { - PDFJS.disableCreateObjectURL = true; - } -})(); - -// Support: Safari 6.0+, iOS -(function checkRangeRequests() { - // Safari has issues with cached range requests see: - // https://github.com/mozilla/pdf.js/issues/3260 - // Last tested with version 6.0.4. - if (isSafari || isIOS) { - PDFJS.disableRange = true; - PDFJS.disableStream = true; - } -})(); - // Provides document.currentScript support // Support: IE, Chrome<29. (function checkCurrentScript() { diff --git a/test/driver.js b/test/driver.js index 91cd268a6..ac7d804ef 100644 --- a/test/driver.js +++ b/test/driver.js @@ -12,12 +12,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* globals PDFJS, pdfjsDistBuildPdf */ +/* globals pdfjsDistBuildPdf, pdfjsDistWebPdfViewer */ 'use strict'; const WAITING_TIME = 100; // ms const PDF_TO_CSS_UNITS = 96.0 / 72.0; +const CMAP_URL = '../external/bcmaps/'; +const CMAP_PACKED = true; const IMAGE_RESOURCES_PATH = '/web/images/'; const WORKER_SRC = '../build/generic/build/pdf.worker.js'; @@ -67,7 +69,7 @@ var rasterizeTextLayer = (function rasterizeTextLayerClosure() { foreignObject.appendChild(div); // Rendering text layer as HTML. - var task = PDFJS.renderTextLayer({ + var task = pdfjsDistBuildPdf.renderTextLayer({ textContent, container: div, viewport, @@ -202,11 +204,11 @@ var rasterizeAnnotationLayer = (function rasterizeAnnotationLayerClosure() { div, annotations, page, - linkService: new PDFJS.SimpleLinkService(), + linkService: new pdfjsDistWebPdfViewer.SimpleLinkService(), imageResourcesPath, renderInteractiveForms, }; - PDFJS.AnnotationLayer.render(parameters); + pdfjsDistBuildPdf.AnnotationLayer.render(parameters); // Inline SVG images from text annotations. var images = div.getElementsByTagName('img'); @@ -269,11 +271,7 @@ var Driver = (function DriverClosure() { // eslint-disable-line no-unused-vars */ function Driver(options) { // Configure the global worker options. - PDFJS.GlobalWorkerOptions.workerSrc = WORKER_SRC; - - PDFJS.cMapPacked = true; - PDFJS.cMapUrl = '../external/bcmaps/'; - PDFJS.pdfBug = true; + pdfjsDistBuildPdf.GlobalWorkerOptions.workerSrc = WORKER_SRC; // Set the passed options this.inflight = options.inflight; @@ -359,13 +357,16 @@ var Driver = (function DriverClosure() { // eslint-disable-line no-unused-vars this._log('Loading file "' + task.file + '"\n'); let absoluteUrl = new URL(task.file, window.location).href; - PDFJS.disableRange = task.disableRange; - PDFJS.disableAutoFetch = !task.enableAutoFetch; try { - PDFJS.getDocument({ + pdfjsDistBuildPdf.getDocument({ url: absoluteUrl, password: task.password, nativeImageDecoderSupport: task.nativeImageDecoderSupport, + cMapUrl: CMAP_URL, + cMapPacked: CMAP_PACKED, + disableRange: task.disableRange, + disableAutoFetch: !task.enableAutoFetch, + pdfBug: true, }).then((doc) => { task.pdfDoc = doc; this._nextPage(task, failure); diff --git a/test/unit/api_spec.js b/test/unit/api_spec.js index f879ba7c3..35e729283 100644 --- a/test/unit/api_spec.js +++ b/test/unit/api_spec.js @@ -58,266 +58,265 @@ describe('api', function() { }, WAIT_TIMEOUT); } - describe('PDFJS', function() { - describe('getDocument', function() { - it('creates pdf doc from URL', function(done) { - var loadingTask = getDocument(basicApiGetDocumentParams); + describe('getDocument', function() { + it('creates pdf doc from URL', function(done) { + var loadingTask = getDocument(basicApiGetDocumentParams); - var isProgressReportedResolved = false; - var progressReportedCapability = createPromiseCapability(); + var isProgressReportedResolved = false; + var progressReportedCapability = createPromiseCapability(); - // Attach the callback that is used to report loading progress; - // similarly to how viewer.js works. - loadingTask.onProgress = function (progressData) { - if (!isProgressReportedResolved) { - isProgressReportedResolved = true; - progressReportedCapability.resolve(progressData); - } - }; + // Attach the callback that is used to report loading progress; + // similarly to how viewer.js works. + loadingTask.onProgress = function (progressData) { + if (!isProgressReportedResolved) { + isProgressReportedResolved = true; + progressReportedCapability.resolve(progressData); + } + }; - var promises = [ - progressReportedCapability.promise, - loadingTask.promise - ]; - Promise.all(promises).then(function (data) { - expect((data[0].loaded / data[0].total) > 0).toEqual(true); - expect(data[1] instanceof PDFDocumentProxy).toEqual(true); - expect(loadingTask).toEqual(data[1].loadingTask); - loadingTask.destroy().then(done); - }).catch(function (reason) { - done.fail(reason); - }); + var promises = [ + progressReportedCapability.promise, + loadingTask.promise + ]; + Promise.all(promises).then(function (data) { + expect((data[0].loaded / data[0].total) > 0).toEqual(true); + expect(data[1] instanceof PDFDocumentProxy).toEqual(true); + expect(loadingTask).toEqual(data[1].loadingTask); + loadingTask.destroy().then(done); + }).catch(function (reason) { + done.fail(reason); }); - it('creates pdf doc from URL and aborts before worker initialized', - function(done) { - var loadingTask = getDocument(basicApiGetDocumentParams); - let destroyed = loadingTask.destroy(); + }); + it('creates pdf doc from URL and aborts before worker initialized', + function(done) { + var loadingTask = getDocument(basicApiGetDocumentParams); + let destroyed = loadingTask.destroy(); - loadingTask.promise.then(function(reason) { - done.fail('shall fail loading'); - }).catch(function (reason) { - expect(true).toEqual(true); - destroyed.then(done); - }); + loadingTask.promise.then(function(reason) { + done.fail('shall fail loading'); + }).catch(function (reason) { + expect(true).toEqual(true); + destroyed.then(done); }); - it('creates pdf doc from URL and aborts loading after worker initialized', - function(done) { - var loadingTask = getDocument(basicApiGetDocumentParams); - // This can be somewhat random -- we cannot guarantee perfect - // 'Terminate' message to the worker before/after setting up pdfManager. - var destroyed = loadingTask._worker.promise.then(function () { - return loadingTask.destroy(); - }); - destroyed.then(function (data) { - expect(true).toEqual(true); - done(); - }).catch(function (reason) { - done.fail(reason); - }); + }); + it('creates pdf doc from URL and aborts loading after worker initialized', + function(done) { + var loadingTask = getDocument(basicApiGetDocumentParams); + // This can be somewhat random -- we cannot guarantee perfect + // 'Terminate' message to the worker before/after setting up pdfManager. + var destroyed = loadingTask._worker.promise.then(function () { + return loadingTask.destroy(); }); - it('creates pdf doc from typed array', function(done) { - var typedArrayPdf; - if (isNodeJS()) { - typedArrayPdf = NodeFileReaderFactory.fetch({ - path: TEST_PDFS_PATH.node + basicApiFileName, - }); + destroyed.then(function (data) { + expect(true).toEqual(true); + done(); + }).catch(function (reason) { + done.fail(reason); + }); + }); + it('creates pdf doc from typed array', function(done) { + var typedArrayPdf; + if (isNodeJS()) { + typedArrayPdf = NodeFileReaderFactory.fetch({ + path: TEST_PDFS_PATH.node + basicApiFileName, + }); + } else { + let nonBinaryRequest = false; + let request = new XMLHttpRequest(); + request.open('GET', TEST_PDFS_PATH.dom + basicApiFileName, false); + try { + request.responseType = 'arraybuffer'; + nonBinaryRequest = request.responseType !== 'arraybuffer'; + } catch (e) { + nonBinaryRequest = true; + } + if (nonBinaryRequest && request.overrideMimeType) { + request.overrideMimeType('text/plain; charset=x-user-defined'); + } + request.send(null); + + if (nonBinaryRequest) { + typedArrayPdf = stringToBytes(request.responseText); } else { - let nonBinaryRequest = false; - let request = new XMLHttpRequest(); - request.open('GET', TEST_PDFS_PATH.dom + basicApiFileName, false); - try { - request.responseType = 'arraybuffer'; - nonBinaryRequest = request.responseType !== 'arraybuffer'; - } catch (e) { - nonBinaryRequest = true; - } - if (nonBinaryRequest && request.overrideMimeType) { - request.overrideMimeType('text/plain; charset=x-user-defined'); - } - request.send(null); - - if (nonBinaryRequest) { - typedArrayPdf = stringToBytes(request.responseText); - } else { - typedArrayPdf = new Uint8Array(request.response); - } + typedArrayPdf = new Uint8Array(request.response); } - // Sanity check to make sure that we fetched the entire PDF file. - expect(typedArrayPdf.length).toEqual(basicApiFileLength); + } + // Sanity check to make sure that we fetched the entire PDF file. + expect(typedArrayPdf.length).toEqual(basicApiFileLength); - var loadingTask = getDocument(typedArrayPdf); - loadingTask.promise.then(function(data) { - expect(data instanceof PDFDocumentProxy).toEqual(true); - loadingTask.destroy().then(done); - }).catch(function (reason) { - done.fail(reason); - }); + var loadingTask = getDocument(typedArrayPdf); + loadingTask.promise.then(function(data) { + expect(data instanceof PDFDocumentProxy).toEqual(true); + loadingTask.destroy().then(done); + }).catch(function (reason) { + done.fail(reason); }); - it('creates pdf doc from invalid PDF file', function(done) { - // A severely corrupt PDF file (even Adobe Reader fails to open it). - var loadingTask = getDocument(buildGetDocumentParams('bug1020226.pdf')); - loadingTask.promise.then(function () { - done.fail('shall fail loading'); - }).catch(function (error) { - expect(error instanceof InvalidPDFException).toEqual(true); - loadingTask.destroy().then(done); - }); + }); + it('creates pdf doc from invalid PDF file', function(done) { + // A severely corrupt PDF file (even Adobe Reader fails to open it). + var loadingTask = getDocument(buildGetDocumentParams('bug1020226.pdf')); + loadingTask.promise.then(function () { + done.fail('shall fail loading'); + }).catch(function (error) { + expect(error instanceof InvalidPDFException).toEqual(true); + loadingTask.destroy().then(done); }); - it('creates pdf doc from non-existent URL', function(done) { - if (isNodeJS()) { - pending('XMLHttpRequest is not supported in Node.js.'); + }); + it('creates pdf doc from non-existent URL', function(done) { + if (isNodeJS()) { + pending('XMLHttpRequest is not supported in Node.js.'); + } + var loadingTask = getDocument( + buildGetDocumentParams('non-existent.pdf')); + loadingTask.promise.then(function(error) { + done.fail('shall fail loading'); + }).catch(function (error) { + expect(error instanceof MissingPDFException).toEqual(true); + loadingTask.destroy().then(done); + }); + }); + it('creates pdf doc from PDF file protected with user and owner password', + function (done) { + var loadingTask = getDocument(buildGetDocumentParams('pr6531_1.pdf')); + + var isPasswordNeededResolved = false; + var passwordNeededCapability = createPromiseCapability(); + var isPasswordIncorrectResolved = false; + var passwordIncorrectCapability = createPromiseCapability(); + + // Attach the callback that is used to request a password; + // similarly to how viewer.js handles passwords. + loadingTask.onPassword = function (updatePassword, reason) { + if (reason === PasswordResponses.NEED_PASSWORD && + !isPasswordNeededResolved) { + isPasswordNeededResolved = true; + passwordNeededCapability.resolve(); + + updatePassword('qwerty'); // Provide an incorrect password. + return; } - var loadingTask = getDocument( - buildGetDocumentParams('non-existent.pdf')); - loadingTask.promise.then(function(error) { - done.fail('shall fail loading'); - }).catch(function (error) { - expect(error instanceof MissingPDFException).toEqual(true); - loadingTask.destroy().then(done); - }); + if (reason === PasswordResponses.INCORRECT_PASSWORD && + !isPasswordIncorrectResolved) { + isPasswordIncorrectResolved = true; + passwordIncorrectCapability.resolve(); + + updatePassword('asdfasdf'); // Provide the correct password. + return; + } + // Shouldn't get here. + expect(false).toEqual(true); + }; + + var promises = [ + passwordNeededCapability.promise, + passwordIncorrectCapability.promise, + loadingTask.promise + ]; + Promise.all(promises).then(function (data) { + expect(data[2] instanceof PDFDocumentProxy).toEqual(true); + loadingTask.destroy().then(done); + }).catch(function (reason) { + done.fail(reason); }); - it('creates pdf doc from PDF file protected with user and owner password', - function (done) { - var loadingTask = getDocument(buildGetDocumentParams('pr6531_1.pdf')); + }); + it('creates pdf doc from PDF file protected with only a user password', + function (done) { + var filename = 'pr6531_2.pdf'; - var isPasswordNeededResolved = false; - var passwordNeededCapability = createPromiseCapability(); - var isPasswordIncorrectResolved = false; - var passwordIncorrectCapability = createPromiseCapability(); - - // Attach the callback that is used to request a password; - // similarly to how viewer.js handles passwords. - loadingTask.onPassword = function (updatePassword, reason) { - if (reason === PasswordResponses.NEED_PASSWORD && - !isPasswordNeededResolved) { - isPasswordNeededResolved = true; - passwordNeededCapability.resolve(); - - updatePassword('qwerty'); // Provide an incorrect password. - return; - } - if (reason === PasswordResponses.INCORRECT_PASSWORD && - !isPasswordIncorrectResolved) { - isPasswordIncorrectResolved = true; - passwordIncorrectCapability.resolve(); - - updatePassword('asdfasdf'); // Provide the correct password. - return; - } - // Shouldn't get here. - expect(false).toEqual(true); - }; - - var promises = [ - passwordNeededCapability.promise, - passwordIncorrectCapability.promise, - loadingTask.promise - ]; - Promise.all(promises).then(function (data) { - expect(data[2] instanceof PDFDocumentProxy).toEqual(true); - loadingTask.destroy().then(done); - }).catch(function (reason) { - done.fail(reason); - }); - }); - it('creates pdf doc from PDF file protected with only a user password', - function (done) { - var filename = 'pr6531_2.pdf'; - - var passwordNeededLoadingTask = getDocument( - buildGetDocumentParams(filename, { - password: '', - })); - var result1 = passwordNeededLoadingTask.promise.then(function () { - done.fail('shall fail with no password'); - return Promise.reject(new Error('loadingTask should be rejected')); - }, function (data) { - expect(data instanceof PasswordException).toEqual(true); - expect(data.code).toEqual(PasswordResponses.NEED_PASSWORD); - return passwordNeededLoadingTask.destroy(); - }); - - var passwordIncorrectLoadingTask = getDocument( - buildGetDocumentParams(filename, { - password: 'qwerty', - })); - var result2 = passwordIncorrectLoadingTask.promise.then(function () { - done.fail('shall fail with wrong password'); - return Promise.reject(new Error('loadingTask should be rejected')); - }, function (data) { - expect(data instanceof PasswordException).toEqual(true); - expect(data.code).toEqual(PasswordResponses.INCORRECT_PASSWORD); - return passwordIncorrectLoadingTask.destroy(); - }); - - var passwordAcceptedLoadingTask = getDocument( - buildGetDocumentParams(filename, { - password: 'asdfasdf', - })); - var result3 = passwordAcceptedLoadingTask.promise.then(function (data) { - expect(data instanceof PDFDocumentProxy).toEqual(true); - return passwordAcceptedLoadingTask.destroy(); - }); - Promise.all([result1, result2, result3]).then(function () { - done(); - }).catch(function (reason) { - done.fail(reason); - }); + var passwordNeededLoadingTask = getDocument( + buildGetDocumentParams(filename, { + password: '', + })); + var result1 = passwordNeededLoadingTask.promise.then(function () { + done.fail('shall fail with no password'); + return Promise.reject(new Error('loadingTask should be rejected')); + }, function (data) { + expect(data instanceof PasswordException).toEqual(true); + expect(data.code).toEqual(PasswordResponses.NEED_PASSWORD); + return passwordNeededLoadingTask.destroy(); }); - it('creates pdf doc from password protected PDF file and aborts/throws ' + - 'in the onPassword callback (issue 7806)', function (done) { - var filename = 'issue3371.pdf'; + var passwordIncorrectLoadingTask = getDocument( + buildGetDocumentParams(filename, { + password: 'qwerty', + })); + var result2 = passwordIncorrectLoadingTask.promise.then(function () { + done.fail('shall fail with wrong password'); + return Promise.reject(new Error('loadingTask should be rejected')); + }, function (data) { + expect(data instanceof PasswordException).toEqual(true); + expect(data.code).toEqual(PasswordResponses.INCORRECT_PASSWORD); + return passwordIncorrectLoadingTask.destroy(); + }); - var passwordNeededLoadingTask = getDocument( - buildGetDocumentParams(filename)); - var passwordIncorrectLoadingTask = getDocument( - buildGetDocumentParams(filename, { - password: 'qwerty', - })); + var passwordAcceptedLoadingTask = getDocument( + buildGetDocumentParams(filename, { + password: 'asdfasdf', + })); + var result3 = passwordAcceptedLoadingTask.promise.then(function (data) { + expect(data instanceof PDFDocumentProxy).toEqual(true); + return passwordAcceptedLoadingTask.destroy(); + }); + Promise.all([result1, result2, result3]).then(function () { + done(); + }).catch(function (reason) { + done.fail(reason); + }); + }); - let passwordNeededDestroyed; - passwordNeededLoadingTask.onPassword = function (callback, reason) { - if (reason === PasswordResponses.NEED_PASSWORD) { - passwordNeededDestroyed = passwordNeededLoadingTask.destroy(); - return; - } - // Shouldn't get here. - expect(false).toEqual(true); - }; - var result1 = passwordNeededLoadingTask.promise.then(function () { - done.fail('shall fail since the loadingTask should be destroyed'); - return Promise.reject(new Error('loadingTask should be rejected')); - }, function (reason) { - expect(reason instanceof PasswordException).toEqual(true); - expect(reason.code).toEqual(PasswordResponses.NEED_PASSWORD); - return passwordNeededDestroyed; - }); + it('creates pdf doc from password protected PDF file and aborts/throws ' + + 'in the onPassword callback (issue 7806)', function (done) { + var filename = 'issue3371.pdf'; - passwordIncorrectLoadingTask.onPassword = function (callback, reason) { - if (reason === PasswordResponses.INCORRECT_PASSWORD) { - throw new Error('Incorrect password'); - } - // Shouldn't get here. - expect(false).toEqual(true); - }; - var result2 = passwordIncorrectLoadingTask.promise.then(function () { - done.fail('shall fail since the onPassword callback should throw'); - return Promise.reject(new Error('loadingTask should be rejected')); - }, function (reason) { - expect(reason instanceof PasswordException).toEqual(true); - expect(reason.code).toEqual(PasswordResponses.INCORRECT_PASSWORD); - return passwordIncorrectLoadingTask.destroy(); - }); + var passwordNeededLoadingTask = getDocument( + buildGetDocumentParams(filename)); + var passwordIncorrectLoadingTask = getDocument( + buildGetDocumentParams(filename, { + password: 'qwerty', + })); - Promise.all([result1, result2]).then(function () { - done(); - }).catch(function (reason) { - done.fail(reason); - }); + let passwordNeededDestroyed; + passwordNeededLoadingTask.onPassword = function (callback, reason) { + if (reason === PasswordResponses.NEED_PASSWORD) { + passwordNeededDestroyed = passwordNeededLoadingTask.destroy(); + return; + } + // Shouldn't get here. + expect(false).toEqual(true); + }; + var result1 = passwordNeededLoadingTask.promise.then(function () { + done.fail('shall fail since the loadingTask should be destroyed'); + return Promise.reject(new Error('loadingTask should be rejected')); + }, function (reason) { + expect(reason instanceof PasswordException).toEqual(true); + expect(reason.code).toEqual(PasswordResponses.NEED_PASSWORD); + return passwordNeededDestroyed; + }); + + passwordIncorrectLoadingTask.onPassword = function (callback, reason) { + if (reason === PasswordResponses.INCORRECT_PASSWORD) { + throw new Error('Incorrect password'); + } + // Shouldn't get here. + expect(false).toEqual(true); + }; + var result2 = passwordIncorrectLoadingTask.promise.then(function () { + done.fail('shall fail since the onPassword callback should throw'); + return Promise.reject(new Error('loadingTask should be rejected')); + }, function (reason) { + expect(reason instanceof PasswordException).toEqual(true); + expect(reason.code).toEqual(PasswordResponses.INCORRECT_PASSWORD); + return passwordIncorrectLoadingTask.destroy(); + }); + + Promise.all([result1, result2]).then(function () { + done(); + }).catch(function (reason) { + done.fail(reason); }); }); }); + describe('PDFWorker', function() { if (isNodeJS()) { pending('Worker is not supported in Node.js.'); diff --git a/test/unit/cmap_spec.js b/test/unit/cmap_spec.js index 8c4c3f5b0..981f695a1 100644 --- a/test/unit/cmap_spec.js +++ b/test/unit/cmap_spec.js @@ -281,8 +281,9 @@ describe('cmap', function() { done.fail('No CMap should be loaded'); }, function (reason) { expect(reason instanceof Error).toEqual(true); - expect(reason.message).toEqual('CMap baseUrl must be specified, ' + - 'see "PDFJS.cMapUrl" (and also "PDFJS.cMapPacked").'); + expect(reason.message).toEqual( + 'The CMap "baseUrl" parameter must be specified, ensure that ' + + 'the "cMapUrl" and "cMapPacked" API parameters are provided.'); done(); }); }); diff --git a/test/unit/test_utils.js b/test/unit/test_utils.js index e57247c3c..c1e0337d4 100644 --- a/test/unit/test_utils.js +++ b/test/unit/test_utils.js @@ -51,8 +51,9 @@ class NodeCMapReaderFactory { fetch({ name, }) { if (!this.baseUrl) { - return Promise.reject(new Error('CMap baseUrl must be specified, ' + - 'see "PDFJS.cMapUrl" (and also "PDFJS.cMapPacked").')); + return Promise.reject(new Error( + 'The CMap "baseUrl" parameter must be specified, ensure that ' + + 'the "cMapUrl" and "cMapPacked" API parameters are provided.')); } if (!name) { return Promise.reject(new Error('CMap name must be specified.')); diff --git a/web/app.js b/web/app.js index 23f00ce8e..015723807 100644 --- a/web/app.js +++ b/web/app.js @@ -22,12 +22,13 @@ import { } from './ui_utils'; import { build, createBlob, getDocument, getFilenameFromUrl, GlobalWorkerOptions, - InvalidPDFException, LinkTarget, MissingPDFException, OPS, PDFJS, PDFWorker, - shadow, UnexpectedResponseException, UNSUPPORTED_FEATURES, version + InvalidPDFException, LinkTarget, MissingPDFException, OPS, PDFWorker, shadow, + UnexpectedResponseException, UNSUPPORTED_FEATURES, version } from 'pdfjs-lib'; import { CursorTool, PDFCursorTools } from './pdf_cursor_tools'; import { PDFRenderingQueue, RenderingStates } from './pdf_rendering_queue'; import { PDFSidebar, SidebarView } from './pdf_sidebar'; +import { AppOptions } from './app_options'; import { getGlobalEventBus } from './dom_events'; import { OverlayManager } from './overlay_manager'; import { PasswordPrompt } from './password_prompt'; @@ -44,39 +45,23 @@ import { PDFThumbnailViewer } from './pdf_thumbnail_viewer'; import { PDFViewer } from './pdf_viewer'; import { SecondaryToolbar } from './secondary_toolbar'; import { Toolbar } from './toolbar'; -import { viewerCompatibilityParams } from './viewer_compatibility'; import { ViewHistory } from './view_history'; const DEFAULT_SCALE_DELTA = 1.1; const DISABLE_AUTO_FETCH_LOADING_BAR_TIMEOUT = 5000; -function configure(PDFJS) { - PDFJS.imageResourcesPath = './images/'; - if (typeof PDFJSDev !== 'undefined' && - PDFJSDev.test('FIREFOX || MOZCENTRAL || GENERIC || CHROME')) { - GlobalWorkerOptions.workerSrc = '../build/pdf.worker.js'; - } - if (typeof PDFJSDev === 'undefined' || !PDFJSDev.test('PRODUCTION')) { - PDFJS.cMapUrl = '../external/bcmaps/'; - GlobalWorkerOptions.workerSrc = '../src/worker_loader.js'; - } else { - PDFJS.cMapUrl = '../web/cmaps/'; - } - PDFJS.cMapPacked = true; -} - const DefaultExternalServices = { updateFindControlState(data) {}, initPassiveLoading(callbacks) {}, fallback(data, callback) {}, reportTelemetry(data) {}, - createDownloadManager() { + createDownloadManager(options) { throw new Error('Not implemented: createDownloadManager'); }, createPreferences() { throw new Error('Not implemented: createPreferences'); }, - createL10n() { + createL10n(options) { throw new Error('Not implemented: createL10n'); }, supportsIntegratedFind: false, @@ -138,19 +123,6 @@ let PDFViewerApplication = { l10n: null, isInitialViewSet: false, downloadComplete: false, - viewerPrefs: { - enableWebGL: false, - sidebarViewOnLoad: SidebarView.NONE, - pdfBugEnabled: false, - showPreviousViewOnLoad: true, - defaultZoomValue: '', - disablePageMode: false, - disablePageLabels: false, - renderer: 'canvas', - textLayerMode: TextLayerMode.ENABLE, - renderInteractiveForms: false, - enablePrintAutoRotate: false, - }, isViewerEmbedded: (window.parent !== window), url: '', baseUrl: '', @@ -161,8 +133,6 @@ let PDFViewerApplication = { // Called once when the document is loaded. initialize(appConfig) { this.preferences = this.externalServices.createPreferences(); - - configure(PDFJS); this.appConfig = appConfig; return this._readPreferences().then(() => { @@ -186,10 +156,10 @@ let PDFViewerApplication = { }); if (this.isViewerEmbedded && - PDFJS.externalLinkTarget === LinkTarget.NONE) { + AppOptions.get('externalLinkTarget') === LinkTarget.NONE) { // Prevent external links from "replacing" the viewer, // when it's embedded in e.g. an iframe or an object. - PDFJS.externalLinkTarget = LinkTarget.TOP; + AppOptions.set('externalLinkTarget', LinkTarget.TOP); } this.initialized = true; @@ -200,74 +170,74 @@ let PDFViewerApplication = { * @private */ _readPreferences() { - let { preferences, viewerPrefs, } = this; + let { preferences, } = this; return Promise.all([ preferences.get('enableWebGL').then(function resolved(value) { - viewerPrefs['enableWebGL'] = value; + AppOptions.set('enableWebGL', value); }), preferences.get('sidebarViewOnLoad').then(function resolved(value) { - viewerPrefs['sidebarViewOnLoad'] = value; + AppOptions.set('sidebarViewOnLoad', value); }), preferences.get('pdfBugEnabled').then(function resolved(value) { - viewerPrefs['pdfBugEnabled'] = value; + AppOptions.set('pdfBugEnabled', value); }), preferences.get('showPreviousViewOnLoad').then(function resolved(value) { - viewerPrefs['showPreviousViewOnLoad'] = value; + AppOptions.set('showPreviousViewOnLoad', value); }), preferences.get('defaultZoomValue').then(function resolved(value) { - viewerPrefs['defaultZoomValue'] = value; + AppOptions.set('defaultZoomValue', value); }), preferences.get('textLayerMode').then(function resolved(value) { - if (viewerPrefs['textLayerMode'] === TextLayerMode.DISABLE) { + if (AppOptions.get('textLayerMode') === TextLayerMode.DISABLE) { return; } - viewerPrefs['textLayerMode'] = value; + AppOptions.set('textLayerMode', value); }), preferences.get('disableRange').then(function resolved(value) { - if (PDFJS.disableRange === true) { + if (AppOptions.get('disableRange') === true) { return; } - PDFJS.disableRange = value; + AppOptions.set('disableRange', value); }), preferences.get('disableStream').then(function resolved(value) { - if (PDFJS.disableStream === true) { + if (AppOptions.get('disableStream') === true) { return; } - PDFJS.disableStream = value; + AppOptions.set('disableStream', value); }), preferences.get('disableAutoFetch').then(function resolved(value) { - PDFJS.disableAutoFetch = value; + AppOptions.set('disableAutoFetch', value); }), preferences.get('disableFontFace').then(function resolved(value) { - if (PDFJS.disableFontFace === true) { + if (AppOptions.get('disableFontFace') === true) { return; } - PDFJS.disableFontFace = value; + AppOptions.set('disableFontFace', value); }), preferences.get('useOnlyCssZoom').then(function resolved(value) { - PDFJS.useOnlyCssZoom = value; + AppOptions.set('useOnlyCssZoom', value); }), preferences.get('externalLinkTarget').then(function resolved(value) { - if (PDFJS.externalLinkTarget !== LinkTarget.NONE) { + if (AppOptions.get('externalLinkTarget') !== LinkTarget.NONE) { return; } - PDFJS.externalLinkTarget = value; + AppOptions.set('externalLinkTarget', value); }), preferences.get('renderer').then(function resolved(value) { - viewerPrefs['renderer'] = value; + AppOptions.set('renderer', value); }), preferences.get('renderInteractiveForms').then(function resolved(value) { - viewerPrefs['renderInteractiveForms'] = value; + AppOptions.set('renderInteractiveForms', value); }), preferences.get('disablePageMode').then(function resolved(value) { - viewerPrefs['disablePageMode'] = value; + AppOptions.set('disablePageMode', value); }), preferences.get('disablePageLabels').then(function resolved(value) { - viewerPrefs['disablePageLabels'] = value; + AppOptions.set('disablePageLabels', value); }), preferences.get('enablePrintAutoRotate').then(function resolved(value) { - viewerPrefs['enablePrintAutoRotate'] = value; + AppOptions.set('enablePrintAutoRotate', value); }), ]).catch(function(reason) { }); }, @@ -276,11 +246,11 @@ let PDFViewerApplication = { * @private */ _parseHashParameters() { - let { appConfig, viewerPrefs, } = this; + let { appConfig, } = this; let waitOn = []; if (typeof PDFJSDev === 'undefined' || !PDFJSDev.test('PRODUCTION') || - viewerPrefs['pdfBugEnabled']) { + AppOptions.get('pdfBugEnabled')) { // Special debugging flags in the hash section of the URL. let hash = document.location.hash.substring(1); let hashParams = parseQueryString(hash); @@ -290,38 +260,42 @@ let PDFViewerApplication = { waitOn.push(loadFakeWorker()); } if ('disablerange' in hashParams) { - PDFJS.disableRange = (hashParams['disablerange'] === 'true'); + AppOptions.set('disableRange', hashParams['disablerange'] === 'true'); } if ('disablestream' in hashParams) { - PDFJS.disableStream = (hashParams['disablestream'] === 'true'); + AppOptions.set('disableStream', hashParams['disablestream'] === 'true'); } if ('disableautofetch' in hashParams) { - PDFJS.disableAutoFetch = (hashParams['disableautofetch'] === 'true'); + AppOptions.set('disableAutoFetch', + hashParams['disableautofetch'] === 'true'); } if ('disablefontface' in hashParams) { - PDFJS.disableFontFace = (hashParams['disablefontface'] === 'true'); + AppOptions.set('disableFontFace', + hashParams['disablefontface'] === 'true'); } if ('disablehistory' in hashParams) { - PDFJS.disableHistory = (hashParams['disablehistory'] === 'true'); + AppOptions.set('disableHistory', + hashParams['disablehistory'] === 'true'); } if ('webgl' in hashParams) { - viewerPrefs['enableWebGL'] = (hashParams['webgl'] === 'true'); + AppOptions.set('enableWebGL', hashParams['webgl'] === 'true'); } if ('useonlycsszoom' in hashParams) { - PDFJS.useOnlyCssZoom = (hashParams['useonlycsszoom'] === 'true'); + AppOptions.set('useOnlyCssZoom', + hashParams['useonlycsszoom'] === 'true'); } if ('verbosity' in hashParams) { - PDFJS.verbosity = hashParams['verbosity'] | 0; + AppOptions.set('verbosity', hashParams['verbosity'] | 0); } if ((typeof PDFJSDev === 'undefined' || !PDFJSDev.test('PRODUCTION')) && hashParams['disablebcmaps'] === 'true') { - PDFJS.cMapUrl = '../external/cmaps/'; - PDFJS.cMapPacked = false; + AppOptions.set('cMapUrl', '../external/cmaps/'); + AppOptions.set('cMapPacked', false); } if ('textlayer' in hashParams) { switch (hashParams['textlayer']) { case 'off': - viewerPrefs['textLayerMode'] = TextLayerMode.DISABLE; + AppOptions.set('textLayerMode', TextLayerMode.DISABLE); break; case 'visible': case 'shadow': @@ -332,7 +306,7 @@ let PDFViewerApplication = { } } if ('pdfbug' in hashParams) { - PDFJS.pdfBug = true; + AppOptions.set('pdfBug', true); let enabled = hashParams['pdfbug'].split(','); waitOn.push(loadAndEnablePDFBug(enabled)); } @@ -341,7 +315,7 @@ let PDFViewerApplication = { // It is not possible to change locale for Firefox extension builds. if ((typeof PDFJSDev === 'undefined' || !PDFJSDev.test('PRODUCTION') || !PDFJSDev.test('FIREFOX || MOZCENTRAL')) && 'locale' in hashParams) { - PDFJS.locale = hashParams['locale']; + AppOptions.set('locale', hashParams['locale']); } } @@ -353,7 +327,7 @@ let PDFViewerApplication = { */ _initializeL10n() { this.l10n = this.externalServices.createL10n({ - locale: PDFJS.locale, + locale: AppOptions.get('locale'), }); return this.l10n.getDirection().then((dir) => { document.getElementsByTagName('html')[0].dir = dir; @@ -364,7 +338,7 @@ let PDFViewerApplication = { * @private */ _initializeViewerComponents() { - let { appConfig, viewerPrefs, } = this; + let { appConfig, } = this; return new Promise((resolve, reject) => { this.overlayManager = new OverlayManager(); @@ -378,12 +352,14 @@ let PDFViewerApplication = { let pdfLinkService = new PDFLinkService({ eventBus, - externalLinkTarget: PDFJS.externalLinkTarget, - externalLinkRel: PDFJS.externalLinkRel, + externalLinkTarget: AppOptions.get('externalLinkTarget'), + externalLinkRel: AppOptions.get('externalLinkRel'), }); this.pdfLinkService = pdfLinkService; - let downloadManager = this.externalServices.createDownloadManager(); + let downloadManager = this.externalServices.createDownloadManager({ + disableCreateObjectURL: AppOptions.get('disableCreateObjectURL'), + }); this.downloadManager = downloadManager; let container = appConfig.mainContainer; @@ -395,15 +371,15 @@ let PDFViewerApplication = { renderingQueue: pdfRenderingQueue, linkService: pdfLinkService, downloadManager, - renderer: viewerPrefs['renderer'], - enableWebGL: viewerPrefs['enableWebGL'], + renderer: AppOptions.get('renderer'), + enableWebGL: AppOptions.get('enableWebGL'), l10n: this.l10n, - textLayerMode: viewerPrefs['textLayerMode'], - imageResourcesPath: PDFJS.imageResourcesPath, - renderInteractiveForms: viewerPrefs['renderInteractiveForms'], - enablePrintAutoRotate: viewerPrefs['enablePrintAutoRotate'], - useOnlyCssZoom: PDFJS.useOnlyCssZoom, - maxCanvasPixels: PDFJS.maxCanvasPixels, + textLayerMode: AppOptions.get('textLayerMode'), + imageResourcesPath: AppOptions.get('imageResourcesPath'), + renderInteractiveForms: AppOptions.get('renderInteractiveForms'), + enablePrintAutoRotate: AppOptions.get('enablePrintAutoRotate'), + useOnlyCssZoom: AppOptions.get('useOnlyCssZoom'), + maxCanvasPixels: AppOptions.get('maxCanvasPixels'), }); pdfRenderingQueue.setViewer(this.pdfViewer); pdfLinkService.setViewer(this.pdfViewer); @@ -568,7 +544,7 @@ let PDFViewerApplication = { support = false; } } - if (support && viewerCompatibilityParams['disableFullscreen'] === true) { + if (support && AppOptions.get('disableFullscreen') === true) { support = false; } @@ -723,6 +699,11 @@ let PDFViewerApplication = { return this.open(file, args); }); } + // Set the necessary global worker parameters, using the available options. + const workerParameters = AppOptions.getAll('worker'); + for (let key in workerParameters) { + GlobalWorkerOptions[key] = workerParameters[key]; + } let parameters = Object.create(null); if (typeof file === 'string') { // URL @@ -740,8 +721,11 @@ let PDFViewerApplication = { PDFJSDev.test('FIREFOX || MOZCENTRAL || CHROME')) { parameters.docBaseUrl = this.baseUrl; } - // TODO: Remove this once all options are moved from the `PDFJS` object. - parameters.verbosity = PDFJS.verbosity; + // Set the necessary API parameters, using the available options. + const apiParameters = AppOptions.getAll('api'); + for (let key in apiParameters) { + parameters[key] = apiParameters[key]; + } if (args) { for (let prop in args) { @@ -952,7 +936,11 @@ let PDFViewerApplication = { // the loading bar will not be completely filled, nor will it be hidden. // To prevent displaying a partially filled loading bar permanently, we // hide it when no data has been loaded during a certain amount of time. - if (PDFJS.disableAutoFetch && percent) { + const disableAutoFetch = this.pdfDocument ? + this.pdfDocument.loadingParams['disableAutoFetch'] : + AppOptions.get('disableAutoFetch'); + + if (disableAutoFetch && percent) { if (this.disableAutoFetchLoadingBarTimeout) { clearTimeout(this.disableAutoFetchLoadingBarTimeout); this.disableAutoFetchLoadingBarTimeout = null; @@ -1013,10 +1001,10 @@ let PDFViewerApplication = { firstPagePromise.then((pdfPage) => { this.loadingBar.setWidth(this.appConfig.viewerContainer); - if (!PDFJS.disableHistory && !this.isViewerEmbedded) { + if (!AppOptions.get('disableHistory') && !this.isViewerEmbedded) { // The browsing history is only enabled when the viewer is standalone, // i.e. not when it is embedded in a web page. - let resetHistory = !this.viewerPrefs['showPreviousViewOnLoad']; + let resetHistory = !AppOptions.get('showPreviousViewOnLoad'); this.pdfHistory.initialize(id, resetHistory); if (this.pdfHistory.initialBookmark) { @@ -1043,19 +1031,19 @@ let PDFViewerApplication = { Promise.all([storePromise, pageModePromise]).then( ([values = {}, pageMode]) => { // Initialize the default values, from user preferences. - let hash = this.viewerPrefs['defaultZoomValue'] ? - ('zoom=' + this.viewerPrefs['defaultZoomValue']) : null; + let hash = AppOptions.get('defaultZoomValue') ? + ('zoom=' + AppOptions.get('defaultZoomValue')) : null; let rotation = null; - let sidebarView = this.viewerPrefs['sidebarViewOnLoad']; + let sidebarView = AppOptions.get('sidebarViewOnLoad'); - if (values.exists && this.viewerPrefs['showPreviousViewOnLoad']) { + if (values.exists && AppOptions.get('showPreviousViewOnLoad')) { hash = 'page=' + values.page + - '&zoom=' + (this.viewerPrefs['defaultZoomValue'] || values.zoom) + + '&zoom=' + (AppOptions.get('defaultZoomValue') || values.zoom) + ',' + values.scrollLeft + ',' + values.scrollTop; rotation = parseInt(values.rotation, 10); sidebarView = sidebarView || (values.sidebarView | 0); } - if (pageMode && !this.viewerPrefs['disablePageMode']) { + if (pageMode && !AppOptions.get('disablePageMode')) { // Always let the user preference/history take precedence. sidebarView = sidebarView || apiPageModeToSidebarView(pageMode); } @@ -1099,7 +1087,7 @@ let PDFViewerApplication = { }); pdfDocument.getPageLabels().then((labels) => { - if (!labels || this.viewerPrefs['disablePageLabels']) { + if (!labels || AppOptions.get('disablePageLabels')) { return; } let i = 0, numLabels = labels.length; @@ -1177,7 +1165,7 @@ let PDFViewerApplication = { info.PDFFormatVersion + ' ' + (info.Producer || '-').trim() + ' / ' + (info.Creator || '-').trim() + ']' + ' (PDF.js: ' + (version || '-') + - (this.viewerPrefs['enableWebGL'] ? ' [WebGL]' : '') + ')'); + (AppOptions.get('enableWebGL') ? ' [WebGL]' : '') + ')'); let pdfTitle; if (metadata && metadata.has('dc:title')) { @@ -1527,6 +1515,9 @@ if (typeof PDFJSDev === 'undefined' || PDFJSDev.test('GENERIC')) { function loadFakeWorker() { return new Promise(function(resolve, reject) { + if (!GlobalWorkerOptions.workerSrc) { + GlobalWorkerOptions.workerSrc = AppOptions.get('workerSrc'); + } if (typeof PDFJSDev === 'undefined' || !PDFJSDev.test('PRODUCTION')) { if (typeof SystemJS === 'object') { SystemJS.import('pdfjs/core/worker').then((worker) => { @@ -1580,12 +1571,12 @@ function webViewerInitialized() { if (typeof PDFJSDev === 'undefined' || PDFJSDev.test('GENERIC')) { let queryString = document.location.search.substring(1); let params = parseQueryString(queryString); - file = 'file' in params ? params.file : appConfig.defaultUrl; + file = 'file' in params ? params.file : AppOptions.get('defaultUrl'); validateFileURL(file); } else if (PDFJSDev.test('FIREFOX || MOZCENTRAL')) { file = window.location.href.split('#')[0]; } else if (PDFJSDev.test('CHROME')) { - file = appConfig.defaultUrl; + file = AppOptions.get('defaultUrl'); } if (typeof PDFJSDev === 'undefined' || PDFJSDev.test('GENERIC')) { @@ -1621,7 +1612,7 @@ function webViewerInitialized() { if (typeof PDFJSDev !== 'undefined' && PDFJSDev.test('FIREFOX || MOZCENTRAL') && !PDFViewerApplication.supportsDocumentFonts) { - PDFJS.disableFontFace = true; + AppOptions.set('disableFontFace', true); PDFViewerApplication.l10n.get('web_fonts_disabled', null, 'Web fonts are disabled: unable to use embedded PDF fonts.'). then((msg) => { @@ -1884,7 +1875,7 @@ if (typeof PDFJSDev === 'undefined' || PDFJSDev.test('GENERIC')) { webViewerFileInputChange = function webViewerFileInputChange(evt) { let file = evt.fileInput.files[0]; - if (!PDFJS.disableCreateObjectURL && URL.createObjectURL) { + if (URL.createObjectURL && !AppOptions.get('disableCreateObjectURL')) { PDFViewerApplication.open(URL.createObjectURL(file)); } else { // Read the local file into a Uint8Array. @@ -2014,7 +2005,7 @@ function webViewerPageChanging(evt) { PDFViewerApplication.pdfThumbnailViewer.scrollThumbnailIntoView(page); } - // we need to update stats + // We need to update stats. if (typeof Stats !== 'undefined' && Stats.enabled) { let pageView = PDFViewerApplication.pdfViewer.getPageView(page - 1); if (pageView && pageView.stats) { diff --git a/web/app_options.js b/web/app_options.js new file mode 100644 index 000000000..c851c9a76 --- /dev/null +++ b/web/app_options.js @@ -0,0 +1,247 @@ +/* Copyright 2018 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { apiCompatibilityParams } from 'pdfjs-lib'; +import { viewerCompatibilityParams } from './viewer_compatibility'; + +const OptionKind = { + VIEWER: 'viewer', + API: 'api', + WORKER: 'worker', +}; + +/** + * PLEASE NOTE: To avoid introducing unnecessary dependencies, we specify the + * values below *explicitly* rather than relying on imported types; + * compare with the format of `default_preferences.json`. + */ +const defaultOptions = { + defaultUrl: { + /** @type {string} */ + value: 'compressed.tracemonkey-pldi-09.pdf', + kind: OptionKind.VIEWER, + }, + defaultZoomValue: { + /** @type {string} */ + value: '', + kind: OptionKind.VIEWER, + }, + disableFullscreen: { + /** @type {boolean} */ + value: viewerCompatibilityParams.disableFullscreen || false, + kind: OptionKind.VIEWER, + }, + disableHistory: { + /** @type {boolean} */ + value: false, + kind: OptionKind.VIEWER, + }, + disablePageLabels: { + /** @type {boolean} */ + value: false, + kind: OptionKind.VIEWER, + }, + disablePageMode: { + /** @type {boolean} */ + value: false, + kind: OptionKind.VIEWER, + }, + enablePrintAutoRotate: { + /** @type {boolean} */ + value: false, + kind: OptionKind.VIEWER, + }, + enableWebGL: { + /** @type {boolean} */ + value: false, + kind: OptionKind.VIEWER, + }, + externalLinkRel: { + /** @type {string} */ + value: 'noopener noreferrer nofollow', + kind: OptionKind.VIEWER, + }, + externalLinkTarget: { + /** @type {number} */ + value: 0, + kind: OptionKind.VIEWER, + }, + imageResourcesPath: { + /** @type {string} */ + value: './images/', + kind: OptionKind.VIEWER, + }, + locale: { + /** @type {string} */ + value: (typeof navigator !== 'undefined' ? navigator.language : 'en-US'), + kind: OptionKind.VIEWER, + }, + maxCanvasPixels: { + /** @type {number} */ + value: viewerCompatibilityParams.maxCanvasPixels || 16777216, + kind: OptionKind.VIEWER, + }, + pdfBugEnabled: { + /** @type {boolean} */ + value: false, + kind: OptionKind.VIEWER, + }, + renderer: { + /** @type {string} */ + value: 'canvas', + kind: OptionKind.VIEWER, + }, + renderInteractiveForms: { + /** @type {boolean} */ + value: false, + kind: OptionKind.VIEWER, + }, + showPreviousViewOnLoad: { + /** @type {boolean} */ + value: true, + kind: OptionKind.VIEWER, + }, + sidebarViewOnLoad: { + /** @type {number} */ + value: 0, + kind: OptionKind.VIEWER, + }, + textLayerMode: { + /** @type {number} */ + value: 1, + kind: OptionKind.VIEWER, + }, + useOnlyCssZoom: { + /** @type {boolean} */ + value: false, + kind: OptionKind.VIEWER, + }, + + cMapPacked: { + /** @type {boolean} */ + value: true, + kind: OptionKind.API, + }, + cMapUrl: { + /** @type {string} */ + value: (typeof PDFJSDev === 'undefined' || !PDFJSDev.test('PRODUCTION') ? + '../external/bcmaps/' : '../web/cmaps/'), + kind: OptionKind.API, + }, + disableAutoFetch: { + /** @type {boolean} */ + value: false, + kind: OptionKind.API, + }, + disableCreateObjectURL: { + /** @type {boolean} */ + value: apiCompatibilityParams.disableCreateObjectURL || false, + kind: OptionKind.API, + }, + disableFontFace: { + /** @type {boolean} */ + value: false, + kind: OptionKind.API, + }, + disableRange: { + /** @type {boolean} */ + value: apiCompatibilityParams.disableRange || false, + kind: OptionKind.API, + }, + disableStream: { + /** @type {boolean} */ + value: apiCompatibilityParams.disableStream || false, + kind: OptionKind.API, + }, + isEvalSupported: { + /** @type {boolean} */ + value: true, + kind: OptionKind.API, + }, + maxImageSize: { + /** @type {number} */ + value: -1, + kind: OptionKind.API, + }, + pdfBug: { + /** @type {boolean} */ + value: false, + kind: OptionKind.API, + }, + postMessageTransfers: { + /** @type {boolean} */ + value: true, + kind: OptionKind.API, + }, + verbosity: { + /** @type {number} */ + value: 1, + kind: OptionKind.API, + }, + + workerPort: { + /** @type {Object} */ + value: null, + kind: OptionKind.WORKER, + }, + workerSrc: { + /** @type {string} */ + value: (typeof PDFJSDev === 'undefined' || !PDFJSDev.test('PRODUCTION') ? + '../src/worker_loader.js' : '../build/pdf.worker.js'), + kind: OptionKind.WORKER, + }, +}; + +const userOptions = Object.create(null); + +class AppOptions { + constructor() { + throw new Error('Cannot initialize AppOptions.'); + } + + static get(name) { + let defaultOption = defaultOptions[name], userOption = userOptions[name]; + if (userOption !== undefined) { + return userOption; + } + return (defaultOption !== undefined ? defaultOption.value : undefined); + } + + static getAll(kind = null) { + let options = Object.create(null); + for (let name in defaultOptions) { + let defaultOption = defaultOptions[name], userOption = userOptions[name]; + if (kind && defaultOption.kind !== kind) { + continue; + } + options[name] = (userOption !== undefined ? + userOption : defaultOption.value); + } + return options; + } + + static set(name, value) { + userOptions[name] = value; + } + + static remove(name) { + delete userOptions[name]; + } +} + +export { + AppOptions, + OptionKind, +}; diff --git a/web/base_viewer.js b/web/base_viewer.js index 2b966379a..bc7955750 100644 --- a/web/base_viewer.js +++ b/web/base_viewer.js @@ -13,7 +13,6 @@ * limitations under the License. */ -import { createPromiseCapability, PDFJS } from 'pdfjs-lib'; import { CSS_UNITS, DEFAULT_SCALE, DEFAULT_SCALE_VALUE, isValidRotation, MAX_AUTO_SCALE, NullL10n, PresentationModeState, RendererType, @@ -21,6 +20,7 @@ import { } from './ui_utils'; import { PDFRenderingQueue, RenderingStates } from './pdf_rendering_queue'; import { AnnotationLayerBuilder } from './annotation_layer_builder'; +import { createPromiseCapability } from 'pdfjs-lib'; import { getGlobalEventBus } from './dom_events'; import { PDFPageView } from './pdf_page_view'; import { SimpleLinkService } from './pdf_link_service'; @@ -408,7 +408,7 @@ class BaseViewer { // starts to create the correct size canvas. Wait until one page is // rendered so we don't tie up too many resources early on. onePageRenderedCapability.promise.then(() => { - if (PDFJS.disableAutoFetch) { + if (pdfDocument.loadingParams['disableAutoFetch']) { // XXX: Printing is semi-broken with auto fetch disabled. pagesCapability.resolve(); return; diff --git a/web/chromecom.js b/web/chromecom.js index a4605b353..20429d8c1 100644 --- a/web/chromecom.js +++ b/web/chromecom.js @@ -363,8 +363,8 @@ ChromeExternalServices.initPassiveLoading = function(callbacks) { callbacks.onOpenWithURL(url, length, originalURL); }); }; -ChromeExternalServices.createDownloadManager = function() { - return new DownloadManager(); +ChromeExternalServices.createDownloadManager = function(options) { + return new DownloadManager(options); }; ChromeExternalServices.createPreferences = function() { return new ChromePreferences(); diff --git a/web/download_manager.js b/web/download_manager.js index 6db6f975c..f0809ae30 100644 --- a/web/download_manager.js +++ b/web/download_manager.js @@ -13,13 +13,18 @@ * limitations under the License. */ -import { createObjectURL, createValidAbsoluteUrl, PDFJS } from 'pdfjs-lib'; +import { + apiCompatibilityParams, createObjectURL, createValidAbsoluteUrl +} from 'pdfjs-lib'; if (typeof PDFJSDev !== 'undefined' && !PDFJSDev.test('CHROME || GENERIC')) { throw new Error('Module "pdfjs-web/download_manager" shall not be used ' + 'outside CHROME and GENERIC builds.'); } +const DISABLE_CREATE_OBJECT_URL = + apiCompatibilityParams.disableCreateObjectURL || false; + function download(blobUrl, filename) { let a = document.createElement('a'); if (!a.click) { @@ -40,6 +45,10 @@ function download(blobUrl, filename) { } class DownloadManager { + constructor({ disableCreateObjectURL = DISABLE_CREATE_OBJECT_URL, }) { + this.disableCreateObjectURL = disableCreateObjectURL; + } + downloadUrl(url, filename) { if (!createValidAbsoluteUrl(url, 'http://example.com')) { return; // restricted/invalid URL @@ -53,7 +62,7 @@ class DownloadManager { filename); } let blobUrl = createObjectURL(data, contentType, - PDFJS.disableCreateObjectURL); + this.disableCreateObjectURL); download(blobUrl, filename); } @@ -66,7 +75,7 @@ class DownloadManager { return; } - if (PDFJS.disableCreateObjectURL) { + if (this.disableCreateObjectURL) { // URL.createObjectURL is not supported this.downloadUrl(url, filename); return; diff --git a/web/firefoxcom.js b/web/firefoxcom.js index c5cb40640..5d7bc5997 100644 --- a/web/firefoxcom.js +++ b/web/firefoxcom.js @@ -84,6 +84,10 @@ let FirefoxCom = (function FirefoxComClosure() { })(); class DownloadManager { + constructor(options) { + this.disableCreateObjectURL = false; + } + downloadUrl(url, filename) { FirefoxCom.request('download', { originalUrl: url, @@ -92,7 +96,7 @@ class DownloadManager { } downloadData(data, filename, contentType) { - let blobUrl = createObjectURL(data, contentType, false); + let blobUrl = createObjectURL(data, contentType); FirefoxCom.request('download', { blobUrl, @@ -256,8 +260,8 @@ PDFViewerApplication.externalServices = { FirefoxCom.request('reportTelemetry', JSON.stringify(data)); }, - createDownloadManager() { - return new DownloadManager(); + createDownloadManager(options) { + return new DownloadManager(options); }, createPreferences() { diff --git a/web/genericcom.js b/web/genericcom.js index 36412a809..89ffd90e3 100644 --- a/web/genericcom.js +++ b/web/genericcom.js @@ -42,14 +42,14 @@ class GenericPreferences extends BasePreferences { } let GenericExternalServices = Object.create(DefaultExternalServices); -GenericExternalServices.createDownloadManager = function() { - return new DownloadManager(); +GenericExternalServices.createDownloadManager = function(options) { + return new DownloadManager(options); }; GenericExternalServices.createPreferences = function() { return new GenericPreferences(); }; -GenericExternalServices.createL10n = function(options) { - return new GenericL10n(options.locale); +GenericExternalServices.createL10n = function({ locale = 'en-US', }) { + return new GenericL10n(locale); }; PDFViewerApplication.externalServices = GenericExternalServices; diff --git a/web/pdf_attachment_viewer.js b/web/pdf_attachment_viewer.js index 27d1b4eab..931b77f37 100644 --- a/web/pdf_attachment_viewer.js +++ b/web/pdf_attachment_viewer.js @@ -14,7 +14,7 @@ */ import { - createObjectURL, createPromiseCapability, getFilenameFromUrl, PDFJS, + createObjectURL, createPromiseCapability, getFilenameFromUrl, removeNullCharacters } from 'pdfjs-lib'; @@ -74,9 +74,9 @@ class PDFAttachmentViewer { * @private */ _bindPdfLink(button, content, filename) { - if (PDFJS.disableCreateObjectURL) { - throw new Error('bindPdfLink: ' + - 'Unsupported "PDFJS.disableCreateObjectURL" value.'); + if (this.downloadManager.disableCreateObjectURL) { + throw new Error( + 'bindPdfLink: Unsupported "disableCreateObjectURL" value.'); } let blobUrl; button.onclick = function() { @@ -141,7 +141,8 @@ class PDFAttachmentViewer { div.className = 'attachmentsItem'; let button = document.createElement('button'); button.textContent = filename; - if (/\.pdf$/i.test(filename) && !PDFJS.disableCreateObjectURL) { + if (/\.pdf$/i.test(filename) && + !this.downloadManager.disableCreateObjectURL) { this._bindPdfLink(button, item.content, filename); } else { this._bindLink(button, item.content, filename); diff --git a/web/pdf_outline_viewer.js b/web/pdf_outline_viewer.js index 05b94016c..6a30b1ebd 100644 --- a/web/pdf_outline_viewer.js +++ b/web/pdf_outline_viewer.js @@ -78,10 +78,10 @@ class PDFOutlineViewer { return; } - element.href = this.linkService.getDestinationHash(dest); + element.href = linkService.getDestinationHash(dest); element.onclick = () => { if (dest) { - this.linkService.navigateTo(dest); + linkService.navigateTo(dest); } return false; }; diff --git a/web/pdf_print_service.js b/web/pdf_print_service.js index 3fc172cd6..f6470745d 100644 --- a/web/pdf_print_service.js +++ b/web/pdf_print_service.js @@ -15,7 +15,6 @@ import { CSS_UNITS, NullL10n } from './ui_utils'; import { PDFPrintServiceFactory, PDFViewerApplication } from './app'; -import { PDFJS } from 'pdfjs-lib'; let activeService = null; let overlayManager = null; @@ -62,6 +61,8 @@ function PDFPrintService(pdfDocument, pagesOverview, printContainer, l10n) { this.pagesOverview = pagesOverview; this.printContainer = printContainer; this.l10n = l10n || NullL10n; + this.disableCreateObjectURL = + pdfDocument.loadingParams['disableCreateObjectURL']; this.currentPage = -1; // The temporary canvas where renderPage paints one page at a time. this.scratchCanvas = document.createElement('canvas'); @@ -153,7 +154,7 @@ PDFPrintService.prototype = { img.style.height = printItem.height; let scratchCanvas = this.scratchCanvas; - if (('toBlob' in scratchCanvas) && !PDFJS.disableCreateObjectURL) { + if (('toBlob' in scratchCanvas) && !this.disableCreateObjectURL) { scratchCanvas.toBlob(function(blob) { img.src = URL.createObjectURL(blob); }); diff --git a/web/pdf_viewer.component.js b/web/pdf_viewer.component.js index de940eaed..34dc65251 100644 --- a/web/pdf_viewer.component.js +++ b/web/pdf_viewer.component.js @@ -12,6 +12,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +/* eslint-disable no-unused-vars */ import { AnnotationLayerBuilder, DefaultAnnotationLayerFactory @@ -25,31 +26,28 @@ import { DownloadManager } from './download_manager.js'; import { GenericL10n } from './genericl10n.js'; import { PDFFindController } from './pdf_find_controller.js'; import { PDFHistory } from './pdf_history.js'; -import pdfjsLib from './pdfjs.js'; import { PDFPageView } from './pdf_page_view.js'; import { PDFSinglePageViewer } from './pdf_single_page_viewer'; import { PDFViewer } from './pdf_viewer.js'; -let { PDFJS, } = pdfjsLib; - -PDFJS.PDFViewer = PDFViewer; -PDFJS.PDFSinglePageViewer = PDFSinglePageViewer; -PDFJS.PDFPageView = PDFPageView; -PDFJS.PDFLinkService = PDFLinkService; -PDFJS.SimpleLinkService = SimpleLinkService; -PDFJS.TextLayerBuilder = TextLayerBuilder; -PDFJS.DefaultTextLayerFactory = DefaultTextLayerFactory; -PDFJS.AnnotationLayerBuilder = AnnotationLayerBuilder; -PDFJS.DefaultAnnotationLayerFactory = DefaultAnnotationLayerFactory; -PDFJS.PDFHistory = PDFHistory; -PDFJS.PDFFindController = PDFFindController; -PDFJS.EventBus = EventBus; - -PDFJS.DownloadManager = DownloadManager; -PDFJS.ProgressBar = ProgressBar; -PDFJS.GenericL10n = GenericL10n; -PDFJS.NullL10n = NullL10n; +const pdfjsVersion = PDFJSDev.eval('BUNDLE_VERSION'); +const pdfjsBuild = PDFJSDev.eval('BUNDLE_BUILD'); export { - PDFJS, + PDFViewer, + PDFSinglePageViewer, + PDFPageView, + PDFLinkService, + SimpleLinkService, + TextLayerBuilder, + DefaultTextLayerFactory, + AnnotationLayerBuilder, + DefaultAnnotationLayerFactory, + PDFHistory, + PDFFindController, + EventBus, + DownloadManager, + ProgressBar, + GenericL10n, + NullL10n, }; diff --git a/web/ui_utils.js b/web/ui_utils.js index ec45ac04c..b289ecd01 100644 --- a/web/ui_utils.js +++ b/web/ui_utils.js @@ -13,7 +13,7 @@ * limitations under the License. */ -import { createPromiseCapability, PDFJS } from 'pdfjs-lib'; +import { createPromiseCapability } from 'pdfjs-lib'; const CSS_UNITS = 96.0 / 72.0; const DEFAULT_SCALE_VALUE = 'auto'; @@ -71,39 +71,6 @@ let NullL10n = { }, }; -/** - * Enables CSS only zooming. - * @var {boolean} - */ -PDFJS.useOnlyCssZoom = (PDFJS.useOnlyCssZoom === undefined ? - false : PDFJS.useOnlyCssZoom); - -/** - * The maximum supported canvas size in total pixels e.g. width * height. - * The default value is 4096 * 4096. Use -1 for no limit. - * @var {number} - */ -PDFJS.maxCanvasPixels = (PDFJS.maxCanvasPixels === undefined ? - 16777216 : PDFJS.maxCanvasPixels); - -/** - * Disables saving of the last position of the viewed PDF. - * @var {boolean} - */ -PDFJS.disableHistory = (PDFJS.disableHistory === undefined ? - false : PDFJS.disableHistory); - -if (typeof PDFJSDev === 'undefined' || - !PDFJSDev.test('FIREFOX || MOZCENTRAL')) { - /** - * Interface locale settings. - * @var {string} - */ - PDFJS.locale = - (PDFJS.locale === undefined && typeof navigator !== 'undefined' ? - navigator.language : PDFJS.locale) || 'en-US'; -} - /** * Returns scale factor for the canvas. It makes sense for the HiDPI displays. * @return {Object} The object with horizontal (sx) and vertical (sy) diff --git a/web/viewer.js b/web/viewer.js index ba680ec65..1c3fbb240 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -16,18 +16,18 @@ 'use strict'; -let DEFAULT_URL = 'compressed.tracemonkey-pldi-09.pdf'; - if (typeof PDFJSDev !== 'undefined' && PDFJSDev.test('CHROME')) { + var defaultUrl; // eslint-disable-line no-var + (function rewriteUrlClosure() { // Run this code outside DOMContentLoaded to make sure that the URL // is rewritten as soon as possible. let queryString = document.location.search.slice(1); let m = /(^|&)file=([^&]*)/.exec(queryString); - DEFAULT_URL = m ? decodeURIComponent(m[2]) : ''; + defaultUrl = m ? decodeURIComponent(m[2]) : ''; // Example: chrome-extension://.../http://example.com/file.pdf - let humanReadableUrl = '/' + DEFAULT_URL + location.hash; + let humanReadableUrl = '/' + defaultUrl + location.hash; history.replaceState(history.state, '', humanReadableUrl); if (top === window) { chrome.runtime.sendMessage('showPageAction'); @@ -35,9 +35,10 @@ if (typeof PDFJSDev !== 'undefined' && PDFJSDev.test('CHROME')) { })(); } -let pdfjsWebApp; +let pdfjsWebApp, pdfjsWebAppOptions; if (typeof PDFJSDev !== 'undefined' && PDFJSDev.test('PRODUCTION')) { pdfjsWebApp = require('./app.js'); + pdfjsWebAppOptions = require('./app_options.js'); } if (typeof PDFJSDev !== 'undefined' && PDFJSDev.test('FIREFOX || MOZCENTRAL')) { @@ -171,7 +172,6 @@ function getViewerConfiguration() { printContainer: document.getElementById('printContainer'), openFileInputName: 'fileInput', debuggerScriptPath: './debugger.js', - defaultUrl: DEFAULT_URL, }; } @@ -180,14 +180,21 @@ function webViewerLoad() { if (typeof PDFJSDev === 'undefined' || !PDFJSDev.test('PRODUCTION')) { Promise.all([ SystemJS.import('pdfjs-web/app'), + SystemJS.import('pdfjs-web/app_options'), SystemJS.import('pdfjs-web/genericcom'), SystemJS.import('pdfjs-web/pdf_print_service'), - ]).then(function([app, ...otherModules]) { + ]).then(function([app, appOptions, ...otherModules]) { window.PDFViewerApplication = app.PDFViewerApplication; + window.PDFViewerApplicationOptions = appOptions.AppOptions; app.PDFViewerApplication.run(config); }); } else { + if (typeof PDFJSDev !== 'undefined' && PDFJSDev.test('CHROME')) { + pdfjsWebAppOptions.AppOptions.set('defaultUrl', defaultUrl); + } + window.PDFViewerApplication = pdfjsWebApp.PDFViewerApplication; + window.PDFViewerApplicationOptions = pdfjsWebAppOptions.AppOptions; pdfjsWebApp.PDFViewerApplication.run(config); } }