diff --git a/src/core/annotation.js b/src/core/annotation.js index c9dfa7faf..229f15707 100644 --- a/src/core/annotation.js +++ b/src/core/annotation.js @@ -16,12 +16,12 @@ import { AnnotationBorderStyleType, AnnotationFieldFlag, AnnotationFlag, - AnnotationType, getInheritableProperty, OPS, stringToBytes, stringToPDFString, - Util, warn + AnnotationType, OPS, stringToBytes, stringToPDFString, Util, warn } from '../shared/util'; import { Catalog, FileSpec, ObjectLoader } from './obj'; import { Dict, isDict, isName, isRef, isStream } from './primitives'; import { ColorSpace } from './colorspace'; +import { getInheritableProperty } from './core_utils'; import { OperatorList } from './operator_list'; import { Stream } from './stream'; diff --git a/src/core/chunked_stream.js b/src/core/chunked_stream.js index c824ce74a..920fc9af0 100644 --- a/src/core/chunked_stream.js +++ b/src/core/chunked_stream.js @@ -15,9 +15,9 @@ /* eslint no-var: error */ import { - arrayByteLength, arraysToBytes, createPromiseCapability, isEmptyObj, - MissingDataException + arrayByteLength, arraysToBytes, createPromiseCapability, isEmptyObj } from '../shared/util'; +import { MissingDataException } from './core_utils'; class ChunkedStream { constructor(length, chunkSize, manager) { diff --git a/src/core/cmap.js b/src/core/cmap.js index 9fa6ffb63..1c0fe238b 100644 --- a/src/core/cmap.js +++ b/src/core/cmap.js @@ -14,11 +14,11 @@ */ import { - CMapCompressionType, FormatError, isString, MissingDataException, unreachable, - warn + CMapCompressionType, FormatError, isString, unreachable, warn } from '../shared/util'; import { isCmd, isEOF, isName, isStream } from './primitives'; import { Lexer } from './parser'; +import { MissingDataException } from './core_utils'; import { Stream } from './stream'; var BUILT_IN_CMAPS = [ diff --git a/src/core/core_utils.js b/src/core/core_utils.js new file mode 100644 index 000000000..a3fa68c5d --- /dev/null +++ b/src/core/core_utils.js @@ -0,0 +1,160 @@ +/* Copyright 2019 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. + */ +/* eslint no-var: error */ + +import { assert, warn } from '../shared/util'; + +function getLookupTableFactory(initializer) { + let lookup; + return function() { + if (initializer) { + lookup = Object.create(null); + initializer(lookup); + initializer = null; + } + return lookup; + }; +} + +const MissingDataException = (function MissingDataExceptionClosure() { + function MissingDataException(begin, end) { + this.begin = begin; + this.end = end; + this.message = `Missing data [${begin}, ${end})`; + } + + MissingDataException.prototype = new Error(); + MissingDataException.prototype.name = 'MissingDataException'; + MissingDataException.constructor = MissingDataException; + + return MissingDataException; +})(); + +const XRefEntryException = (function XRefEntryExceptionClosure() { + function XRefEntryException(msg) { + this.message = msg; + } + + XRefEntryException.prototype = new Error(); + XRefEntryException.prototype.name = 'XRefEntryException'; + XRefEntryException.constructor = XRefEntryException; + + return XRefEntryException; +})(); + +const XRefParseException = (function XRefParseExceptionClosure() { + function XRefParseException(msg) { + this.message = msg; + } + + XRefParseException.prototype = new Error(); + XRefParseException.prototype.name = 'XRefParseException'; + XRefParseException.constructor = XRefParseException; + + return XRefParseException; +})(); + +/** + * Get the value of an inheritable property. + * + * If the PDF specification explicitly lists a property in a dictionary as + * inheritable, then the value of the property may be present in the dictionary + * itself or in one or more parents of the dictionary. + * + * If the key is not found in the tree, `undefined` is returned. Otherwise, + * the value for the key is returned or, if `stopWhenFound` is `false`, a list + * of values is returned. To avoid infinite loops, the traversal is stopped when + * the loop limit is reached. + * + * @param {Dict} dict - Dictionary from where to start the traversal. + * @param {string} key - The key of the property to find the value for. + * @param {boolean} getArray - Whether or not the value should be fetched as an + * array. The default value is `false`. + * @param {boolean} stopWhenFound - Whether or not to stop the traversal when + * the key is found. If set to `false`, we always walk up the entire parent + * chain, for example to be able to find `\Resources` placed on multiple + * levels of the tree. The default value is `true`. + */ +function getInheritableProperty({ dict, key, getArray = false, + stopWhenFound = true, }) { + const LOOP_LIMIT = 100; + let loopCount = 0; + let values; + + while (dict) { + const value = getArray ? dict.getArray(key) : dict.get(key); + if (value !== undefined) { + if (stopWhenFound) { + return value; + } + if (!values) { + values = []; + } + values.push(value); + } + if (++loopCount > LOOP_LIMIT) { + warn(`getInheritableProperty: maximum loop count exceeded for "${key}"`); + break; + } + dict = dict.get('Parent'); + } + return values; +} + +const ROMAN_NUMBER_MAP = [ + '', 'C', 'CC', 'CCC', 'CD', 'D', 'DC', 'DCC', 'DCCC', 'CM', + '', 'X', 'XX', 'XXX', 'XL', 'L', 'LX', 'LXX', 'LXXX', 'XC', + '', 'I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX' +]; + +/** + * Converts positive integers to (upper case) Roman numerals. + * @param {integer} number - The number that should be converted. + * @param {boolean} lowerCase - Indicates if the result should be converted + * to lower case letters. The default value is `false`. + * @return {string} The resulting Roman number. + */ +function toRomanNumerals(number, lowerCase = false) { + assert(Number.isInteger(number) && number > 0, + 'The number should be a positive integer.'); + let pos, romanBuf = []; + // Thousands + while (number >= 1000) { + number -= 1000; + romanBuf.push('M'); + } + // Hundreds + pos = (number / 100) | 0; + number %= 100; + romanBuf.push(ROMAN_NUMBER_MAP[pos]); + // Tens + pos = (number / 10) | 0; + number %= 10; + romanBuf.push(ROMAN_NUMBER_MAP[10 + pos]); + // Ones + romanBuf.push(ROMAN_NUMBER_MAP[20 + number]); + + const romanStr = romanBuf.join(''); + return (lowerCase ? romanStr.toLowerCase() : romanStr); +} + +export { + getLookupTableFactory, + MissingDataException, + XRefEntryException, + XRefParseException, + getInheritableProperty, + toRomanNumerals, +}; diff --git a/src/core/document.js b/src/core/document.js index b525bace9..228f505e8 100644 --- a/src/core/document.js +++ b/src/core/document.js @@ -15,12 +15,15 @@ /* eslint no-var: error */ import { - assert, FormatError, getInheritableProperty, info, isArrayBuffer, isBool, - isNum, isSpace, isString, MissingDataException, OPS, shadow, stringToBytes, - stringToPDFString, Util, warn, XRefEntryException, XRefParseException + assert, FormatError, info, isArrayBuffer, isBool, isNum, isSpace, isString, + OPS, shadow, stringToBytes, stringToPDFString, Util, warn } from '../shared/util'; import { Catalog, ObjectLoader, XRef } from './obj'; import { Dict, isDict, isName, isStream, Ref } from './primitives'; +import { + getInheritableProperty, MissingDataException, XRefEntryException, + XRefParseException +} from './core_utils'; import { NullStream, Stream, StreamsSequenceStream } from './stream'; import { AnnotationFactory } from './annotation'; import { calculateMD5 } from './crypto'; diff --git a/src/core/evaluator.js b/src/core/evaluator.js index cd2841155..556d13454 100644 --- a/src/core/evaluator.js +++ b/src/core/evaluator.js @@ -15,9 +15,9 @@ import { AbortException, assert, CMapCompressionType, createPromiseCapability, - FONT_IDENTITY_MATRIX, FormatError, getLookupTableFactory, IDENTITY_MATRIX, - info, isNum, isString, NativeImageDecoding, OPS, stringToPDFString, - TextRenderingMode, UNSUPPORTED_FEATURES, Util, warn + FONT_IDENTITY_MATRIX, FormatError, IDENTITY_MATRIX, info, isNum, isString, + NativeImageDecoding, OPS, stringToPDFString, TextRenderingMode, + UNSUPPORTED_FEATURES, Util, warn } from '../shared/util'; import { CMapFactory, IdentityCMap } from './cmap'; import { DecodeStream, Stream } from './stream'; @@ -42,6 +42,7 @@ import { Lexer, Parser } from './parser'; import { bidi } from './bidi'; import { ColorSpace } from './colorspace'; import { getGlyphsUnicode } from './glyphlist'; +import { getLookupTableFactory } from './core_utils'; import { getMetrics } from './metrics'; import { isPDFFunction } from './function'; import { JpegStream } from './jpeg_stream'; diff --git a/src/core/fonts.js b/src/core/fonts.js index a52525127..c7ebbdebf 100644 --- a/src/core/fonts.js +++ b/src/core/fonts.js @@ -15,8 +15,7 @@ import { assert, bytesToString, FONT_IDENTITY_MATRIX, FontType, FormatError, info, - isNum, isSpace, MissingDataException, readUint32, shadow, string32, - unreachable, warn + isNum, isSpace, readUint32, shadow, string32, unreachable, warn } from '../shared/util'; import { CFF, CFFCharset, CFFCompiler, CFFHeader, CFFIndex, CFFParser, CFFPrivateDict, @@ -36,6 +35,7 @@ import { } from './unicode'; import { FontRendererFactory } from './font_renderer'; import { IdentityCMap } from './cmap'; +import { MissingDataException } from './core_utils'; import { Stream } from './stream'; import { Type1Parser } from './type1_parser'; diff --git a/src/core/glyphlist.js b/src/core/glyphlist.js index d1ded4715..0317ddbbd 100644 --- a/src/core/glyphlist.js +++ b/src/core/glyphlist.js @@ -14,7 +14,7 @@ */ /* no-babel-preset */ -var getLookupTableFactory = require('../shared/util').getLookupTableFactory; +var getLookupTableFactory = require('./core_utils').getLookupTableFactory; var getGlyphsUnicode = getLookupTableFactory(function (t) { t['A'] = 0x0041; diff --git a/src/core/metrics.js b/src/core/metrics.js index 88b3d1542..04741c554 100644 --- a/src/core/metrics.js +++ b/src/core/metrics.js @@ -13,7 +13,7 @@ * limitations under the License. */ -import { getLookupTableFactory } from '../shared/util'; +import { getLookupTableFactory } from './core_utils'; // The Metrics object contains glyph widths (in glyph space units). // As per PDF spec, for most fonts (Type 3 being an exception) a glyph diff --git a/src/core/obj.js b/src/core/obj.js index 484460f8d..251613358 100644 --- a/src/core/obj.js +++ b/src/core/obj.js @@ -15,15 +15,17 @@ import { bytesToString, createPromiseCapability, createValidAbsoluteUrl, FormatError, - info, InvalidPDFException, isBool, isNum, isString, MissingDataException, - PermissionFlag, shadow, stringToPDFString, stringToUTF8String, - toRomanNumerals, unreachable, warn, XRefEntryException, XRefParseException + info, InvalidPDFException, isBool, isNum, isString, PermissionFlag, shadow, + stringToPDFString, stringToUTF8String, unreachable, warn } from '../shared/util'; import { Dict, isCmd, isDict, isName, isRef, isRefsEqual, isStream, Ref, RefSet, RefSetCache } from './primitives'; import { Lexer, Parser } from './parser'; +import { + MissingDataException, toRomanNumerals, XRefEntryException, XRefParseException +} from './core_utils'; import { ChunkedStream } from './chunked_stream'; import { CipherTransformFactory } from './crypto'; import { ColorSpace } from './colorspace'; diff --git a/src/core/parser.js b/src/core/parser.js index c0a76bbb6..c01001fca 100644 --- a/src/core/parser.js +++ b/src/core/parser.js @@ -19,7 +19,7 @@ import { } from './stream'; import { assert, bytesToString, FormatError, info, isNum, isSpace, isString, - MissingDataException, StreamType, warn + StreamType, warn } from '../shared/util'; import { Cmd, Dict, EOF, isCmd, isDict, isEOF, isName, Name, Ref @@ -28,6 +28,7 @@ import { CCITTFaxStream } from './ccitt_stream'; import { Jbig2Stream } from './jbig2_stream'; import { JpegStream } from './jpeg_stream'; import { JpxStream } from './jpx_stream'; +import { MissingDataException } from './core_utils'; const MAX_LENGTH_TO_CACHE = 1000; const MAX_ADLER32_LENGTH = 5552; diff --git a/src/core/pattern.js b/src/core/pattern.js index 83e622c43..f7fb2274f 100644 --- a/src/core/pattern.js +++ b/src/core/pattern.js @@ -15,11 +15,11 @@ /* eslint-disable no-multi-spaces */ import { - assert, FormatError, info, MissingDataException, unreachable, - UNSUPPORTED_FEATURES, Util, warn + assert, FormatError, info, unreachable, UNSUPPORTED_FEATURES, Util, warn } from '../shared/util'; import { ColorSpace } from './colorspace'; import { isStream } from './primitives'; +import { MissingDataException } from './core_utils'; var ShadingType = { FUNCTION_BASED: 1, diff --git a/src/core/pdf_manager.js b/src/core/pdf_manager.js index abe2b7df1..36a1729df 100644 --- a/src/core/pdf_manager.js +++ b/src/core/pdf_manager.js @@ -14,9 +14,10 @@ */ import { - createValidAbsoluteUrl, MissingDataException, shadow, unreachable, warn + createValidAbsoluteUrl, shadow, unreachable, warn } from '../shared/util'; import { ChunkedStreamManager } from './chunked_stream'; +import { MissingDataException } from './core_utils'; import { PDFDocument } from './document'; import { Stream } from './stream'; diff --git a/src/core/standard_fonts.js b/src/core/standard_fonts.js index 9ead2b1c7..c21834b89 100644 --- a/src/core/standard_fonts.js +++ b/src/core/standard_fonts.js @@ -14,7 +14,7 @@ */ /* eslint no-var: error */ -import { getLookupTableFactory } from '../shared/util'; +import { getLookupTableFactory } from './core_utils'; /** * Hold a map of decoded fonts and of the standard fourteen Type1 diff --git a/src/core/unicode.js b/src/core/unicode.js index c5ec32c08..f0b362a85 100644 --- a/src/core/unicode.js +++ b/src/core/unicode.js @@ -14,7 +14,7 @@ */ /* no-babel-preset */ -var getLookupTableFactory = require('../shared/util').getLookupTableFactory; +var getLookupTableFactory = require('./core_utils').getLookupTableFactory; // Some characters, e.g. copyrightserif, are mapped to the private use area // and might not be displayed using standard fonts. Mapping/hacking well-known diff --git a/src/core/worker.js b/src/core/worker.js index 46daf0a27..8827c1099 100644 --- a/src/core/worker.js +++ b/src/core/worker.js @@ -17,12 +17,13 @@ import { arrayByteLength, arraysToBytes, assert, createPromiseCapability, info, InvalidPDFException, MissingPDFException, PasswordException, setVerbosityLevel, UnexpectedResponseException, UnknownErrorException, - UNSUPPORTED_FEATURES, warn, XRefParseException + UNSUPPORTED_FEATURES, warn } from '../shared/util'; import { LocalPdfManager, NetworkPdfManager } from './pdf_manager'; import isNodeJS from '../shared/is_node'; import { MessageHandler } from '../shared/message_handler'; import { Ref } from './primitives'; +import { XRefParseException } from './core_utils'; var WorkerTask = (function WorkerTaskClosure() { function WorkerTask(name) { diff --git a/src/display/annotation_layer.js b/src/display/annotation_layer.js index 5b66faba9..b568731d7 100644 --- a/src/display/annotation_layer.js +++ b/src/display/annotation_layer.js @@ -15,7 +15,7 @@ import { addLinkAttributes, DOMSVGFactory, getFilenameFromUrl, LinkTarget -} from './dom_utils'; +} from './display_utils'; import { AnnotationBorderStyleType, AnnotationType, stringToPDFString, unreachable, Util, warn diff --git a/src/display/api.js b/src/display/api.js index 271aaead3..04eda7517 100644 --- a/src/display/api.js +++ b/src/display/api.js @@ -25,7 +25,7 @@ import { import { DOMCanvasFactory, DOMCMapReaderFactory, DummyStatTimer, loadScript, PageViewport, RenderingCancelledException, StatTimer -} from './dom_utils'; +} from './display_utils'; import { FontFaceObject, FontLoader } from './font_loader'; import { apiCompatibilityParams } from './api_compatibility'; import { CanvasGraphics } from './canvas'; diff --git a/src/display/dom_utils.js b/src/display/display_utils.js similarity index 100% rename from src/display/dom_utils.js rename to src/display/display_utils.js diff --git a/src/display/svg.js b/src/display/svg.js index e36e2c73b..755c87b9f 100644 --- a/src/display/svg.js +++ b/src/display/svg.js @@ -18,7 +18,7 @@ import { createObjectURL, FONT_IDENTITY_MATRIX, IDENTITY_MATRIX, ImageKind, isNum, OPS, TextRenderingMode, Util, warn } from '../shared/util'; -import { DOMSVGFactory } from './dom_utils'; +import { DOMSVGFactory } from './display_utils'; import isNodeJS from '../shared/is_node'; var SVGGraphics = function() { diff --git a/src/license_header.js b/src/license_header.js index 988b465f2..d167af68c 100644 --- a/src/license_header.js +++ b/src/license_header.js @@ -1,4 +1,4 @@ -/* Copyright 2018 Mozilla Foundation +/* Copyright 2019 Mozilla Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/src/license_header_libre.js b/src/license_header_libre.js index 12d6738b7..1aaaf048d 100644 --- a/src/license_header_libre.js +++ b/src/license_header_libre.js @@ -2,7 +2,7 @@ * @licstart The following is the entire license notice for the * Javascript code in this page * - * Copyright 2018 Mozilla Foundation + * Copyright 2019 Mozilla Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/src/pdf.js b/src/pdf.js index 7681115c4..3b84f475c 100644 --- a/src/pdf.js +++ b/src/pdf.js @@ -25,7 +25,7 @@ var pdfjsSharedUtil = require('./shared/util.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 pdfjsDisplayDisplayUtils = require('./display/display_utils.js'); var pdfjsDisplaySVG = require('./display/svg.js'); let pdfjsDisplayWorkerOptions = require('./display/worker_options.js'); let pdfjsDisplayAPICompatibility = require('./display/api_compatibility.js'); @@ -107,11 +107,11 @@ exports.Util = pdfjsSharedUtil.Util; exports.ReadableStream = pdfjsSharedUtil.ReadableStream; exports.URL = pdfjsSharedUtil.URL; exports.RenderingCancelledException = - pdfjsDisplayDOMUtils.RenderingCancelledException; -exports.getFilenameFromUrl = pdfjsDisplayDOMUtils.getFilenameFromUrl; -exports.LinkTarget = pdfjsDisplayDOMUtils.LinkTarget; -exports.addLinkAttributes = pdfjsDisplayDOMUtils.addLinkAttributes; -exports.loadScript = pdfjsDisplayDOMUtils.loadScript; + pdfjsDisplayDisplayUtils.RenderingCancelledException; +exports.getFilenameFromUrl = pdfjsDisplayDisplayUtils.getFilenameFromUrl; +exports.LinkTarget = pdfjsDisplayDisplayUtils.LinkTarget; +exports.addLinkAttributes = pdfjsDisplayDisplayUtils.addLinkAttributes; +exports.loadScript = pdfjsDisplayDisplayUtils.loadScript; exports.GlobalWorkerOptions = pdfjsDisplayWorkerOptions.GlobalWorkerOptions; exports.apiCompatibilityParams = pdfjsDisplayAPICompatibility.apiCompatibilityParams; diff --git a/src/shared/util.js b/src/shared/util.js index 29993afd7..4d03b26e8 100644 --- a/src/shared/util.js +++ b/src/shared/util.js @@ -382,18 +382,6 @@ function shadow(obj, prop, value) { return value; } -function getLookupTableFactory(initializer) { - var lookup; - return function () { - if (initializer) { - lookup = Object.create(null); - initializer(lookup); - initializer = null; - } - return lookup; - }; -} - var PasswordException = (function PasswordExceptionClosure() { function PasswordException(msg, code) { this.name = 'PasswordException'; @@ -458,44 +446,6 @@ var UnexpectedResponseException = return UnexpectedResponseException; })(); -var MissingDataException = (function MissingDataExceptionClosure() { - function MissingDataException(begin, end) { - this.begin = begin; - this.end = end; - this.message = 'Missing data [' + begin + ', ' + end + ')'; - } - - MissingDataException.prototype = new Error(); - MissingDataException.prototype.name = 'MissingDataException'; - MissingDataException.constructor = MissingDataException; - - return MissingDataException; -})(); - -const XRefEntryException = (function XRefEntryExceptionClosure() { - function XRefEntryException(msg) { - this.message = msg; - } - - XRefEntryException.prototype = new Error(); - XRefEntryException.prototype.name = 'XRefEntryException'; - XRefEntryException.constructor = XRefEntryException; - - return XRefEntryException; -})(); - -var XRefParseException = (function XRefParseExceptionClosure() { - function XRefParseException(msg) { - this.message = msg; - } - - XRefParseException.prototype = new Error(); - XRefParseException.prototype.name = 'XRefParseException'; - XRefParseException.constructor = XRefParseException; - - return XRefParseException; -})(); - /** * Error caused during parsing PDF data. */ @@ -659,53 +609,6 @@ function isEvalSupported() { } } -/** - * Get the value of an inheritable property. - * - * If the PDF specification explicitly lists a property in a dictionary as - * inheritable, then the value of the property may be present in the dictionary - * itself or in one or more parents of the dictionary. - * - * If the key is not found in the tree, `undefined` is returned. Otherwise, - * the value for the key is returned or, if `stopWhenFound` is `false`, a list - * of values is returned. To avoid infinite loops, the traversal is stopped when - * the loop limit is reached. - * - * @param {Dict} dict - Dictionary from where to start the traversal. - * @param {string} key - The key of the property to find the value for. - * @param {boolean} getArray - Whether or not the value should be fetched as an - * array. The default value is `false`. - * @param {boolean} stopWhenFound - Whether or not to stop the traversal when - * the key is found. If set to `false`, we always walk up the entire parent - * chain, for example to be able to find `\Resources` placed on multiple - * levels of the tree. The default value is `true`. - */ -function getInheritableProperty({ dict, key, getArray = false, - stopWhenFound = true, }) { - const LOOP_LIMIT = 100; - let loopCount = 0; - let values; - - while (dict) { - const value = getArray ? dict.getArray(key) : dict.get(key); - if (value !== undefined) { - if (stopWhenFound) { - return value; - } - if (!values) { - values = []; - } - values.push(value); - } - if (++loopCount > LOOP_LIMIT) { - warn(`getInheritableProperty: maximum loop count exceeded for "${key}"`); - break; - } - dict = dict.get('Parent'); - } - return values; -} - var Util = (function UtilClosure() { function Util() {} @@ -866,43 +769,6 @@ var Util = (function UtilClosure() { return Util; })(); -const ROMAN_NUMBER_MAP = [ - '', 'C', 'CC', 'CCC', 'CD', 'D', 'DC', 'DCC', 'DCCC', 'CM', - '', 'X', 'XX', 'XXX', 'XL', 'L', 'LX', 'LXX', 'LXXX', 'XC', - '', 'I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX' -]; - -/** - * Converts positive integers to (upper case) Roman numerals. - * @param {integer} number - The number that should be converted. - * @param {boolean} lowerCase - Indicates if the result should be converted - * to lower case letters. The default value is `false`. - * @return {string} The resulting Roman number. - */ -function toRomanNumerals(number, lowerCase = false) { - assert(Number.isInteger(number) && number > 0, - 'The number should be a positive integer.'); - let pos, romanBuf = []; - // Thousands - while (number >= 1000) { - number -= 1000; - romanBuf.push('M'); - } - // Hundreds - pos = (number / 100) | 0; - number %= 100; - romanBuf.push(ROMAN_NUMBER_MAP[pos]); - // Tens - pos = (number / 10) | 0; - number %= 10; - romanBuf.push(ROMAN_NUMBER_MAP[10 + pos]); - // Ones - romanBuf.push(ROMAN_NUMBER_MAP[20 + number]); - - const romanStr = romanBuf.join(''); - return (lowerCase ? romanStr.toLowerCase() : romanStr); -} - const PDFStringTranslateTable = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2D8, 0x2C7, 0x2C6, 0x2D9, 0x2DD, 0x2DB, 0x2DA, 0x2DC, 0, 0, 0, 0, 0, 0, 0, @@ -1046,7 +912,6 @@ export { CMapCompressionType, AbortException, InvalidPDFException, - MissingDataException, MissingPDFException, NativeImageDecoding, PasswordException, @@ -1057,9 +922,6 @@ export { UnexpectedResponseException, UnknownErrorException, Util, - toRomanNumerals, - XRefEntryException, - XRefParseException, FormatError, arrayByteLength, arraysToBytes, @@ -1068,8 +930,6 @@ export { createPromiseCapability, createObjectURL, deprecated, - getInheritableProperty, - getLookupTableFactory, getVerbosityLevel, info, isArrayBuffer, diff --git a/test/unit/api_spec.js b/test/unit/api_spec.js index 83bb8edf4..56d744d6b 100644 --- a/test/unit/api_spec.js +++ b/test/unit/api_spec.js @@ -23,7 +23,7 @@ import { } from '../../src/shared/util'; import { DOMCanvasFactory, RenderingCancelledException, StatTimer -} from '../../src/display/dom_utils'; +} from '../../src/display/display_utils'; import { getDocument, PDFDataRangeTransport, PDFDocumentProxy, PDFPageProxy, PDFWorker } from '../../src/display/api'; diff --git a/test/unit/clitests.json b/test/unit/clitests.json index 9aa5a7b12..66122437d 100644 --- a/test/unit/clitests.json +++ b/test/unit/clitests.json @@ -12,10 +12,11 @@ "cff_parser_spec.js", "cmap_spec.js", "colorspace_spec.js", + "core_utils_spec.js", "crypto_spec.js", "display_svg_spec.js", + "display_utils_spec.js", "document_spec.js", - "dom_utils_spec.js", "encodings_spec.js", "evaluator_spec.js", "function_spec.js", diff --git a/test/unit/cmap_spec.js b/test/unit/cmap_spec.js index 981f695a1..88b0cefd1 100644 --- a/test/unit/cmap_spec.js +++ b/test/unit/cmap_spec.js @@ -14,7 +14,7 @@ */ import { CMap, CMapFactory, IdentityCMap } from '../../src/core/cmap'; -import { DOMCMapReaderFactory } from '../../src/display/dom_utils'; +import { DOMCMapReaderFactory } from '../../src/display/display_utils'; import isNodeJS from '../../src/shared/is_node'; import { Name } from '../../src/core/primitives'; import { NodeCMapReaderFactory } from './test_utils'; diff --git a/test/unit/core_utils_spec.js b/test/unit/core_utils_spec.js new file mode 100644 index 000000000..fcdcadff8 --- /dev/null +++ b/test/unit/core_utils_spec.js @@ -0,0 +1,158 @@ +/* Copyright 2019 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 { Dict, Ref } from '../../src/core/primitives'; +import { + getInheritableProperty, toRomanNumerals +} from '../../src/core/core_utils'; +import { XRefMock } from './test_utils'; + +describe('core_utils', function() { + describe('getInheritableProperty', function() { + it('handles non-dictionary arguments', function() { + expect(getInheritableProperty({ dict: null, key: 'foo', })) + .toEqual(undefined); + expect(getInheritableProperty({ dict: undefined, key: 'foo', })) + .toEqual(undefined); + }); + + it('handles dictionaries that do not contain the property', function() { + // Empty dictionary. + const emptyDict = new Dict(); + expect(getInheritableProperty({ dict: emptyDict, key: 'foo', })) + .toEqual(undefined); + + // Filled dictionary with a different property. + const filledDict = new Dict(); + filledDict.set('bar', 'baz'); + expect(getInheritableProperty({ dict: filledDict, key: 'foo', })) + .toEqual(undefined); + }); + + it('fetches the property if it is not inherited', function() { + const ref = new Ref(10, 0); + const xref = new XRefMock([{ ref, data: 'quux', }]); + const dict = new Dict(xref); + + // Regular values should be fetched. + dict.set('foo', 'bar'); + expect(getInheritableProperty({ dict, key: 'foo', })).toEqual('bar'); + + // Array value should be fetched (with references resolved). + dict.set('baz', ['qux', ref]); + expect(getInheritableProperty({ dict, key: 'baz', getArray: true, })) + .toEqual(['qux', 'quux']); + }); + + it('fetches the property if it is inherited and present on one level', + function() { + const ref = new Ref(10, 0); + const xref = new XRefMock([{ ref, data: 'quux', }]); + const firstDict = new Dict(xref); + const secondDict = new Dict(xref); + firstDict.set('Parent', secondDict); + + // Regular values should be fetched. + secondDict.set('foo', 'bar'); + expect(getInheritableProperty({ dict: firstDict, key: 'foo', })) + .toEqual('bar'); + + // Array value should be fetched (with references resolved). + secondDict.set('baz', ['qux', ref]); + expect(getInheritableProperty({ dict: firstDict, key: 'baz', + getArray: true, })) + .toEqual(['qux', 'quux']); + }); + + it('fetches the property if it is inherited and present on multiple levels', + function() { + const ref = new Ref(10, 0); + const xref = new XRefMock([{ ref, data: 'quux', }]); + const firstDict = new Dict(xref); + const secondDict = new Dict(xref); + firstDict.set('Parent', secondDict); + + // Regular values should be fetched. + firstDict.set('foo', 'bar1'); + secondDict.set('foo', 'bar2'); + expect(getInheritableProperty({ dict: firstDict, key: 'foo', })) + .toEqual('bar1'); + expect(getInheritableProperty({ dict: firstDict, key: 'foo', + getArray: false, stopWhenFound: false, })) + .toEqual(['bar1', 'bar2']); + + // Array value should be fetched (with references resolved). + firstDict.set('baz', ['qux1', ref]); + secondDict.set('baz', ['qux2', ref]); + expect(getInheritableProperty({ dict: firstDict, key: 'baz', + getArray: true, stopWhenFound: false, })) + .toEqual([['qux1', 'quux'], ['qux2', 'quux']]); + }); + + it('stops searching when the loop limit is reached', function() { + const dict = new Dict(); + let currentDict = dict; + let parentDict = null; + for (let i = 0; i < 150; i++) { // Exceeds the loop limit of 100. + parentDict = new Dict(); + currentDict.set('Parent', parentDict); + currentDict = parentDict; + } + parentDict.set('foo', 'bar'); // Never found because of loop limit. + expect(getInheritableProperty({ dict, key: 'foo', })).toEqual(undefined); + + dict.set('foo', 'baz'); + expect(getInheritableProperty({ dict, key: 'foo', getArray: false, + stopWhenFound: false, })) + .toEqual(['baz']); + }); + }); + + describe('toRomanNumerals', function() { + it('handles invalid arguments', function() { + for (const input of ['foo', -1, 0]) { + expect(function() { + toRomanNumerals(input); + }).toThrow(new Error('The number should be a positive integer.')); + } + }); + + it('converts numbers to uppercase Roman numerals', function() { + expect(toRomanNumerals(1)).toEqual('I'); + expect(toRomanNumerals(6)).toEqual('VI'); + expect(toRomanNumerals(7)).toEqual('VII'); + expect(toRomanNumerals(8)).toEqual('VIII'); + expect(toRomanNumerals(10)).toEqual('X'); + expect(toRomanNumerals(40)).toEqual('XL'); + expect(toRomanNumerals(100)).toEqual('C'); + expect(toRomanNumerals(500)).toEqual('D'); + expect(toRomanNumerals(1000)).toEqual('M'); + expect(toRomanNumerals(2019)).toEqual('MMXIX'); + }); + + it('converts numbers to lowercase Roman numerals', function() { + expect(toRomanNumerals(1, /* lowercase = */ true)).toEqual('i'); + expect(toRomanNumerals(6, /* lowercase = */ true)).toEqual('vi'); + expect(toRomanNumerals(7, /* lowercase = */ true)).toEqual('vii'); + expect(toRomanNumerals(8, /* lowercase = */ true)).toEqual('viii'); + expect(toRomanNumerals(10, /* lowercase = */ true)).toEqual('x'); + expect(toRomanNumerals(40, /* lowercase = */ true)).toEqual('xl'); + expect(toRomanNumerals(100, /* lowercase = */ true)).toEqual('c'); + expect(toRomanNumerals(500, /* lowercase = */ true)).toEqual('d'); + expect(toRomanNumerals(1000, /* lowercase = */ true)).toEqual('m'); + expect(toRomanNumerals(2019, /* lowercase = */ true)).toEqual('mmxix'); + }); + }); +}); diff --git a/test/unit/custom_spec.js b/test/unit/custom_spec.js index e729dc37b..d44cc5bab 100644 --- a/test/unit/custom_spec.js +++ b/test/unit/custom_spec.js @@ -14,7 +14,7 @@ */ import { buildGetDocumentParams, NodeCanvasFactory } from './test_utils'; -import { DOMCanvasFactory } from '../../src/display/dom_utils'; +import { DOMCanvasFactory } from '../../src/display/display_utils'; import { getDocument } from '../../src/display/api'; import isNodeJS from '../../src/shared/is_node'; diff --git a/test/unit/dom_utils_spec.js b/test/unit/display_utils_spec.js similarity index 95% rename from test/unit/dom_utils_spec.js rename to test/unit/display_utils_spec.js index 938aafd83..474cefe8e 100644 --- a/test/unit/dom_utils_spec.js +++ b/test/unit/display_utils_spec.js @@ -13,10 +13,12 @@ * limitations under the License. */ -import { DOMSVGFactory, getFilenameFromUrl } from '../../src/display/dom_utils'; +import { + DOMSVGFactory, getFilenameFromUrl +} from '../../src/display/display_utils'; import isNodeJS from '../../src/shared/is_node'; -describe('dom_utils', function() { +describe('display_utils', function() { describe('DOMSVGFactory', function() { let svgFactory; diff --git a/test/unit/jasmine-boot.js b/test/unit/jasmine-boot.js index baff368da..d0e5e5800 100644 --- a/test/unit/jasmine-boot.js +++ b/test/unit/jasmine-boot.js @@ -53,11 +53,12 @@ function initializePDFJS(callback) { 'pdfjs-test/unit/cff_parser_spec', 'pdfjs-test/unit/cmap_spec', 'pdfjs-test/unit/colorspace_spec', + 'pdfjs-test/unit/core_utils_spec', 'pdfjs-test/unit/crypto_spec', 'pdfjs-test/unit/custom_spec', 'pdfjs-test/unit/display_svg_spec', + 'pdfjs-test/unit/display_utils_spec', 'pdfjs-test/unit/document_spec', - 'pdfjs-test/unit/dom_utils_spec', 'pdfjs-test/unit/encodings_spec', 'pdfjs-test/unit/evaluator_spec', 'pdfjs-test/unit/function_spec', diff --git a/test/unit/util_spec.js b/test/unit/util_spec.js index 5d626837a..a28eb8eb5 100644 --- a/test/unit/util_spec.js +++ b/test/unit/util_spec.js @@ -14,13 +14,11 @@ */ import { - bytesToString, createPromiseCapability, createValidAbsoluteUrl, - getInheritableProperty, isArrayBuffer, isBool, isEmptyObj, isNum, - isSameOrigin, isSpace, isString, log2, ReadableStream, removeNullCharacters, - string32, stringToBytes, stringToPDFString, toRomanNumerals, URL + bytesToString, createPromiseCapability, createValidAbsoluteUrl, isArrayBuffer, + isBool, isEmptyObj, isNum, isSameOrigin, isSpace, isString, log2, + ReadableStream, removeNullCharacters, string32, stringToBytes, + stringToPDFString, URL } from '../../src/shared/util'; -import { Dict, Ref } from '../../src/core/primitives'; -import { XRefMock } from './test_utils'; describe('util', function() { describe('bytesToString', function() { @@ -54,106 +52,6 @@ describe('util', function() { }); }); - describe('getInheritableProperty', function() { - it('handles non-dictionary arguments', function() { - expect(getInheritableProperty({ dict: null, key: 'foo', })) - .toEqual(undefined); - expect(getInheritableProperty({ dict: undefined, key: 'foo', })) - .toEqual(undefined); - }); - - it('handles dictionaries that do not contain the property', function() { - // Empty dictionary. - const emptyDict = new Dict(); - expect(getInheritableProperty({ dict: emptyDict, key: 'foo', })) - .toEqual(undefined); - - // Filled dictionary with a different property. - const filledDict = new Dict(); - filledDict.set('bar', 'baz'); - expect(getInheritableProperty({ dict: filledDict, key: 'foo', })) - .toEqual(undefined); - }); - - it('fetches the property if it is not inherited', function() { - const ref = new Ref(10, 0); - const xref = new XRefMock([{ ref, data: 'quux', }]); - const dict = new Dict(xref); - - // Regular values should be fetched. - dict.set('foo', 'bar'); - expect(getInheritableProperty({ dict, key: 'foo', })).toEqual('bar'); - - // Array value should be fetched (with references resolved). - dict.set('baz', ['qux', ref]); - expect(getInheritableProperty({ dict, key: 'baz', getArray: true, })) - .toEqual(['qux', 'quux']); - }); - - it('fetches the property if it is inherited and present on one level', - function() { - const ref = new Ref(10, 0); - const xref = new XRefMock([{ ref, data: 'quux', }]); - const firstDict = new Dict(xref); - const secondDict = new Dict(xref); - firstDict.set('Parent', secondDict); - - // Regular values should be fetched. - secondDict.set('foo', 'bar'); - expect(getInheritableProperty({ dict: firstDict, key: 'foo', })) - .toEqual('bar'); - - // Array value should be fetched (with references resolved). - secondDict.set('baz', ['qux', ref]); - expect(getInheritableProperty({ dict: firstDict, key: 'baz', - getArray: true, })) - .toEqual(['qux', 'quux']); - }); - - it('fetches the property if it is inherited and present on multiple levels', - function() { - const ref = new Ref(10, 0); - const xref = new XRefMock([{ ref, data: 'quux', }]); - const firstDict = new Dict(xref); - const secondDict = new Dict(xref); - firstDict.set('Parent', secondDict); - - // Regular values should be fetched. - firstDict.set('foo', 'bar1'); - secondDict.set('foo', 'bar2'); - expect(getInheritableProperty({ dict: firstDict, key: 'foo', })) - .toEqual('bar1'); - expect(getInheritableProperty({ dict: firstDict, key: 'foo', - getArray: false, stopWhenFound: false, })) - .toEqual(['bar1', 'bar2']); - - // Array value should be fetched (with references resolved). - firstDict.set('baz', ['qux1', ref]); - secondDict.set('baz', ['qux2', ref]); - expect(getInheritableProperty({ dict: firstDict, key: 'baz', - getArray: true, stopWhenFound: false, })) - .toEqual([['qux1', 'quux'], ['qux2', 'quux']]); - }); - - it('stops searching when the loop limit is reached', function() { - const dict = new Dict(); - let currentDict = dict; - let parentDict = null; - for (let i = 0; i < 150; i++) { // Exceeds the loop limit of 100. - parentDict = new Dict(); - currentDict.set('Parent', parentDict); - currentDict = parentDict; - } - parentDict.set('foo', 'bar'); // Never found because of loop limit. - expect(getInheritableProperty({ dict, key: 'foo', })).toEqual(undefined); - - dict.set('foo', 'baz'); - expect(getInheritableProperty({ dict, key: 'foo', getArray: false, - stopWhenFound: false, })) - .toEqual(['baz']); - }); - }); - describe('isArrayBuffer', function() { it('handles array buffer values', function() { expect(isArrayBuffer(new ArrayBuffer(0))).toEqual(true); @@ -321,42 +219,6 @@ describe('util', function() { }); }); - describe('toRomanNumerals', function() { - it('handles invalid arguments', function() { - for (const input of ['foo', -1, 0]) { - expect(function() { - toRomanNumerals(input); - }).toThrow(new Error('The number should be a positive integer.')); - } - }); - - it('converts numbers to uppercase Roman numerals', function() { - expect(toRomanNumerals(1)).toEqual('I'); - expect(toRomanNumerals(6)).toEqual('VI'); - expect(toRomanNumerals(7)).toEqual('VII'); - expect(toRomanNumerals(8)).toEqual('VIII'); - expect(toRomanNumerals(10)).toEqual('X'); - expect(toRomanNumerals(40)).toEqual('XL'); - expect(toRomanNumerals(100)).toEqual('C'); - expect(toRomanNumerals(500)).toEqual('D'); - expect(toRomanNumerals(1000)).toEqual('M'); - expect(toRomanNumerals(2019)).toEqual('MMXIX'); - }); - - it('converts numbers to lowercase Roman numerals', function() { - expect(toRomanNumerals(1, /* lowercase = */ true)).toEqual('i'); - expect(toRomanNumerals(6, /* lowercase = */ true)).toEqual('vi'); - expect(toRomanNumerals(7, /* lowercase = */ true)).toEqual('vii'); - expect(toRomanNumerals(8, /* lowercase = */ true)).toEqual('viii'); - expect(toRomanNumerals(10, /* lowercase = */ true)).toEqual('x'); - expect(toRomanNumerals(40, /* lowercase = */ true)).toEqual('xl'); - expect(toRomanNumerals(100, /* lowercase = */ true)).toEqual('c'); - expect(toRomanNumerals(500, /* lowercase = */ true)).toEqual('d'); - expect(toRomanNumerals(1000, /* lowercase = */ true)).toEqual('m'); - expect(toRomanNumerals(2019, /* lowercase = */ true)).toEqual('mmxix'); - }); - }); - describe('URL', function() { it('should return an Object', function() { const url = new URL('https://example.com');