From 0e1b5589e7a54f979e5e572024b71222c9444ebc Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Sat, 6 Jan 2018 13:10:58 +0100 Subject: [PATCH] Restore the `btoa`/`atob` polyfills for Node.js These were removed in PR 9170, since they were unused in the browsers that we'll support in PDF.js version `2.0`. However looking at the output of Travis, where a subset of the unit-tests are run using Node.js, there's warnings about `btoa` being undefined. This doesn't appear to cause any errors, which probably explains why we didn't notice this before (despite PR 9201). --- examples/node/domstubs.js | 5 ----- gulpfile.js | 9 ++++++++- src/core/worker.js | 7 ++++--- src/display/svg.js | 5 +++-- src/pdf.js | 3 ++- src/shared/compatibility.js | 23 +++++++++++++++++++++++ src/shared/is_node.js | 19 +++++++++++++++++++ src/shared/util.js | 6 ------ test/unit/api_spec.js | 6 +++--- test/unit/cmap_spec.js | 2 +- test/unit/custom_spec.js | 2 +- test/unit/display_svg_spec.js | 3 ++- test/unit/dom_utils_spec.js | 2 +- test/unit/node_stream_spec.js | 3 ++- test/unit/test_utils.js | 3 ++- test/unit/ui_utils_spec.js | 3 ++- 16 files changed, 73 insertions(+), 28 deletions(-) create mode 100644 src/shared/is_node.js diff --git a/examples/node/domstubs.js b/examples/node/domstubs.js index 2efa7c0ac..fcd54c8ea 100644 --- a/examples/node/domstubs.js +++ b/examples/node/domstubs.js @@ -197,10 +197,6 @@ DOMElementSerializer.prototype = { }, }; -function btoa (chars) { - return Buffer.from(chars, 'binary').toString('base64'); -} - const document = { childNodes : [], @@ -245,7 +241,6 @@ Image.prototype = { } } -exports.btoa = btoa; exports.document = document; exports.Image = Image; diff --git a/gulpfile.js b/gulpfile.js index 74c590e52..830033209 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -1015,10 +1015,17 @@ gulp.task('lib', ['buildnumber'], function () { var licenseHeaderLibre = fs.readFileSync('./src/license_header_libre.js').toString(); var preprocessor2 = require('./external/builder/preprocessor2.js'); + var sharedFiles = [ + 'compatibility', + 'global_scope', + 'is_node', + 'streams_polyfill', + 'util', + ]; var buildLib = merge([ gulp.src([ 'src/{core,display}/*.js', - 'src/shared/{compatibility,util,streams_polyfill,global_scope}.js', + 'src/shared/{' + sharedFiles.join() + '}.js', 'src/{pdf,pdf.worker}.js', ], { base: 'src/', }), gulp.src([ diff --git a/src/core/worker.js b/src/core/worker.js index dda90c8bf..0326bf4f4 100644 --- a/src/core/worker.js +++ b/src/core/worker.js @@ -15,11 +15,12 @@ import { arrayByteLength, arraysToBytes, assert, createPromiseCapability, info, - InvalidPDFException, isNodeJS, MessageHandler, MissingPDFException, - PasswordException, setVerbosityLevel, UnexpectedResponseException, - UnknownErrorException, UNSUPPORTED_FEATURES, warn, XRefParseException + InvalidPDFException, MessageHandler, MissingPDFException, PasswordException, + setVerbosityLevel, UnexpectedResponseException, UnknownErrorException, + UNSUPPORTED_FEATURES, warn, XRefParseException } from '../shared/util'; import { LocalPdfManager, NetworkPdfManager } from './pdf_manager'; +import isNodeJS from '../shared/is_node'; import { Ref } from './primitives'; var WorkerTask = (function WorkerTaskClosure() { diff --git a/src/display/svg.js b/src/display/svg.js index 2b5b9a5e5..1322114b2 100644 --- a/src/display/svg.js +++ b/src/display/svg.js @@ -15,10 +15,11 @@ /* globals __non_webpack_require__ */ import { - createObjectURL, FONT_IDENTITY_MATRIX, IDENTITY_MATRIX, ImageKind, isNodeJS, - isNum, OPS, Util, warn + createObjectURL, FONT_IDENTITY_MATRIX, IDENTITY_MATRIX, ImageKind, isNum, OPS, + Util, warn } from '../shared/util'; import { DOMSVGFactory } from './dom_utils'; +import isNodeJS from '../shared/is_node'; var SVGGraphics = function() { throw new Error('Not implemented: SVGGraphics'); diff --git a/src/pdf.js b/src/pdf.js index 0d7ed0ca3..b0e90b3aa 100644 --- a/src/pdf.js +++ b/src/pdf.js @@ -31,7 +31,8 @@ var pdfjsDisplaySVG = require('./display/svg.js'); if (typeof PDFJSDev === 'undefined' || !PDFJSDev.test('FIREFOX || MOZCENTRAL')) { - if (pdfjsSharedUtil.isNodeJS()) { + const isNodeJS = require('./shared/is_node.js'); + if (isNodeJS()) { var PDFNodeStream = require('./display/node_stream.js').PDFNodeStream; pdfjsDisplayAPI.setPDFNetworkStreamClass(PDFNodeStream); } else if (typeof Response !== 'undefined' && 'body' in Response.prototype && diff --git a/src/shared/compatibility.js b/src/shared/compatibility.js index b371d4c19..742d3aa85 100644 --- a/src/shared/compatibility.js +++ b/src/shared/compatibility.js @@ -22,6 +22,7 @@ if ((typeof PDFJSDev === 'undefined' || (typeof PDFJS === 'undefined' || !PDFJS.compatibilityChecked)) { var globalScope = require('./global_scope'); +const isNodeJS = require('./is_node'); var userAgent = (typeof navigator !== 'undefined' && navigator.userAgent) || ''; var isAndroid = /Android/.test(userAgent); @@ -41,6 +42,28 @@ if (typeof PDFJS === 'undefined') { PDFJS.compatibilityChecked = true; +// Support: Node.js +(function checkNodeBtoa() { + if (globalScope.btoa || !isNodeJS()) { + return; + } + globalScope.btoa = function(chars) { + // eslint-disable-next-line no-undef + return Buffer.from(chars, 'binary').toString('base64'); + }; +})(); + +// Support: Node.js +(function checkNodeAtob() { + if (globalScope.atob || !isNodeJS()) { + return; + } + globalScope.atob = function(input) { + // eslint-disable-next-line no-undef + return Buffer.from(input, 'base64').toString('binary'); + }; +})(); + // Checks if possible to use URL.createObjectURL() // Support: IE, Chrome on iOS (function checkOnBlobSupport() { diff --git a/src/shared/is_node.js b/src/shared/is_node.js new file mode 100644 index 000000000..1ab845300 --- /dev/null +++ b/src/shared/is_node.js @@ -0,0 +1,19 @@ +/* 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. + */ +/* globals module, process */ + +module.exports = function isNodeJS() { + return typeof process === 'object' && process + '' === '[object process]'; +}; diff --git a/src/shared/util.js b/src/shared/util.js index 93d6f1583..593b0135f 100644 --- a/src/shared/util.js +++ b/src/shared/util.js @@ -1089,11 +1089,6 @@ function isSpace(ch) { return (ch === 0x20 || ch === 0x09 || ch === 0x0D || ch === 0x0A); } -function isNodeJS() { - // eslint-disable-next-line no-undef - return typeof process === 'object' && process + '' === '[object process]'; -} - /** * Promise Capability object. * @@ -1633,7 +1628,6 @@ export { isNum, isString, isSpace, - isNodeJS, isSameOrigin, createValidAbsoluteUrl, isLittleEndian, diff --git a/test/unit/api_spec.js b/test/unit/api_spec.js index 30fcc7b18..d67596a31 100644 --- a/test/unit/api_spec.js +++ b/test/unit/api_spec.js @@ -17,9 +17,8 @@ import { buildGetDocumentParams, NodeFileReaderFactory, TEST_PDFS_PATH } from './test_utils'; import { - createPromiseCapability, FontType, InvalidPDFException, isNodeJS, - MissingPDFException, PasswordException, PasswordResponses, StreamType, - stringToBytes + createPromiseCapability, FontType, InvalidPDFException, MissingPDFException, + PasswordException, PasswordResponses, StreamType, stringToBytes } from '../../src/shared/util'; import { DOMCanvasFactory, RenderingCancelledException @@ -27,6 +26,7 @@ import { import { getDocument, PDFDocumentProxy, PDFPageProxy } from '../../src/display/api'; +import isNodeJS from '../../src/shared/is_node'; import { PDFJS } from '../../src/display/global'; describe('api', function() { diff --git a/test/unit/cmap_spec.js b/test/unit/cmap_spec.js index 457d146eb..8c4c3f5b0 100644 --- a/test/unit/cmap_spec.js +++ b/test/unit/cmap_spec.js @@ -15,7 +15,7 @@ import { CMap, CMapFactory, IdentityCMap } from '../../src/core/cmap'; import { DOMCMapReaderFactory } from '../../src/display/dom_utils'; -import { isNodeJS } from '../../src/shared/util'; +import isNodeJS from '../../src/shared/is_node'; import { Name } from '../../src/core/primitives'; import { NodeCMapReaderFactory } from './test_utils'; import { StringStream } from '../../src/core/stream'; diff --git a/test/unit/custom_spec.js b/test/unit/custom_spec.js index 4e4fedce7..40ad3e62b 100644 --- a/test/unit/custom_spec.js +++ b/test/unit/custom_spec.js @@ -16,7 +16,7 @@ import { buildGetDocumentParams } from './test_utils'; import { DOMCanvasFactory } from '../../src/display/dom_utils'; import { getDocument } from '../../src/display/api'; -import { isNodeJS } from '../../src/shared/util'; +import isNodeJS from '../../src/shared/is_node'; function getTopLeftPixel(canvasContext) { let imgData = canvasContext.getImageData(0, 0, 1, 1); diff --git a/test/unit/display_svg_spec.js b/test/unit/display_svg_spec.js index 46f047d11..4278836ff 100644 --- a/test/unit/display_svg_spec.js +++ b/test/unit/display_svg_spec.js @@ -14,10 +14,11 @@ */ /* globals __non_webpack_require__ */ -import { isNodeJS, NativeImageDecoding } from '../../src/shared/util'; import { setStubs, unsetStubs } from '../../examples/node/domstubs'; import { buildGetDocumentParams } from './test_utils'; import { getDocument } from '../../src/display/api'; +import isNodeJS from '../../src/shared/is_node'; +import { NativeImageDecoding } from '../../src/shared/util'; import { SVGGraphics } from '../../src/display/svg'; const XLINK_NS = 'http://www.w3.org/1999/xlink'; diff --git a/test/unit/dom_utils_spec.js b/test/unit/dom_utils_spec.js index ab1f82d4f..314459450 100644 --- a/test/unit/dom_utils_spec.js +++ b/test/unit/dom_utils_spec.js @@ -16,7 +16,7 @@ import { DOMSVGFactory, getFilenameFromUrl, isExternalLinkTargetSet, LinkTarget } from '../../src/display/dom_utils'; -import { isNodeJS } from '../../src/shared/util'; +import isNodeJS from '../../src/shared/is_node'; import { PDFJS } from '../../src/display/global'; describe('dom_utils', function() { diff --git a/test/unit/node_stream_spec.js b/test/unit/node_stream_spec.js index 784c8cfac..e1231acca 100644 --- a/test/unit/node_stream_spec.js +++ b/test/unit/node_stream_spec.js @@ -14,7 +14,8 @@ */ /* globals __non_webpack_require__ */ -import { assert, isNodeJS } from '../../src/shared/util'; +import { assert } from '../../src/shared/util'; +import isNodeJS from '../../src/shared/is_node'; import { PDFNodeStream } from '../../src/display/node_stream'; // Make sure that we only running this script is Node.js environments. diff --git a/test/unit/test_utils.js b/test/unit/test_utils.js index 205c7c3a6..db6253e02 100644 --- a/test/unit/test_utils.js +++ b/test/unit/test_utils.js @@ -13,7 +13,8 @@ * limitations under the License. */ -import { CMapCompressionType, isNodeJS } from '../../src/shared/util'; +import { CMapCompressionType } from '../../src/shared/util'; +import isNodeJS from '../../src/shared/is_node'; import { isRef } from '../../src/core/primitives'; class NodeFileReaderFactory { diff --git a/test/unit/ui_utils_spec.js b/test/unit/ui_utils_spec.js index bae36b51d..4765dcaf4 100644 --- a/test/unit/ui_utils_spec.js +++ b/test/unit/ui_utils_spec.js @@ -17,7 +17,8 @@ import { binarySearchFirstItem, EventBus, getPDFFileNameFromURL, isValidRotation, waitOnEventOrTimeout, WaitOnType } from '../../web/ui_utils'; -import { createObjectURL, isNodeJS } from '../../src/shared/util'; +import { createObjectURL } from '../../src/shared/util'; +import isNodeJS from '../../src/shared/is_node'; describe('ui_utils', function() { describe('binary search', function() {