Merge pull request #9887 from Snuffleupagus/rm-Util-inherit

Convert more code in the `/src` folder to use ES6 classes, such that `Util.inherit` can be removed
This commit is contained in:
Tim van der Meij 2018-07-14 23:58:38 +02:00 committed by GitHub
commit b56081c5f8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 358 additions and 387 deletions

View File

@ -14,8 +14,8 @@
*/
import {
CMapCompressionType, FormatError, isString, MissingDataException,
unreachable, Util, warn
CMapCompressionType, FormatError, isString, MissingDataException, unreachable,
warn
} from '../shared/util';
import { isCmd, isEOF, isName, isStream } from './primitives';
import { Lexer } from './parser';
@ -194,8 +194,8 @@ var BUILT_IN_CMAPS = [
'WP-Symbol'];
// CMap, not to be confused with TrueType's cmap.
var CMap = (function CMapClosure() {
function CMap(builtInCMap) {
class CMap {
constructor(builtInCMap = false) {
// Codespace ranges are stored as follows:
// [[1BytePairs], [2BytePairs], [3BytePairs], [4BytePairs]]
// where nBytePairs are ranges e.g. [low1, high1, low2, high2, ...]
@ -211,204 +211,193 @@ var CMap = (function CMapClosure() {
this.useCMap = null;
this.builtInCMap = builtInCMap;
}
CMap.prototype = {
addCodespaceRange(n, low, high) {
this.codespaceRanges[n - 1].push(low, high);
this.numCodespaceRanges++;
},
mapCidRange(low, high, dstLow) {
while (low <= high) {
this._map[low++] = dstLow++;
}
},
addCodespaceRange(n, low, high) {
this.codespaceRanges[n - 1].push(low, high);
this.numCodespaceRanges++;
}
mapBfRange(low, high, dstLow) {
var lastByte = dstLow.length - 1;
while (low <= high) {
this._map[low++] = dstLow;
// Only the last byte has to be incremented.
dstLow = dstLow.substr(0, lastByte) +
String.fromCharCode(dstLow.charCodeAt(lastByte) + 1);
}
},
mapCidRange(low, high, dstLow) {
while (low <= high) {
this._map[low++] = dstLow++;
}
}
mapBfRangeToArray(low, high, array) {
var i = 0, ii = array.length;
while (low <= high && i < ii) {
this._map[low] = array[i++];
++low;
}
},
mapBfRange(low, high, dstLow) {
var lastByte = dstLow.length - 1;
while (low <= high) {
this._map[low++] = dstLow;
// Only the last byte has to be incremented.
dstLow = dstLow.substr(0, lastByte) +
String.fromCharCode(dstLow.charCodeAt(lastByte) + 1);
}
}
// This is used for both bf and cid chars.
mapOne(src, dst) {
this._map[src] = dst;
},
mapBfRangeToArray(low, high, array) {
let i = 0, ii = array.length;
while (low <= high && i < ii) {
this._map[low] = array[i++];
++low;
}
}
lookup(code) {
return this._map[code];
},
// This is used for both bf and cid chars.
mapOne(src, dst) {
this._map[src] = dst;
}
contains(code) {
return this._map[code] !== undefined;
},
lookup(code) {
return this._map[code];
}
forEach(callback) {
// Most maps have fewer than 65536 entries, and for those we use normal
// array iteration. But really sparse tables are possible -- e.g. with
// indices in the *billions*. For such tables we use for..in, which isn't
// ideal because it stringifies the indices for all present elements, but
// it does avoid iterating over every undefined entry.
let map = this._map;
let length = map.length;
if (length <= 0x10000) {
for (let i = 0; i < length; i++) {
if (map[i] !== undefined) {
callback(i, map[i]);
}
}
} else {
for (let i in map) {
contains(code) {
return this._map[code] !== undefined;
}
forEach(callback) {
// Most maps have fewer than 65536 entries, and for those we use normal
// array iteration. But really sparse tables are possible -- e.g. with
// indices in the *billions*. For such tables we use for..in, which isn't
// ideal because it stringifies the indices for all present elements, but
// it does avoid iterating over every undefined entry.
let map = this._map;
let length = map.length;
if (length <= 0x10000) {
for (let i = 0; i < length; i++) {
if (map[i] !== undefined) {
callback(i, map[i]);
}
}
},
charCodeOf(value) {
// `Array.prototype.indexOf` is *extremely* inefficient for arrays which
// are both very sparse and very large (see issue8372.pdf).
let map = this._map;
if (map.length <= 0x10000) {
return map.indexOf(value);
} else {
for (let i in map) {
callback(i, map[i]);
}
for (let charCode in map) {
if (map[charCode] === value) {
return (charCode | 0);
}
}
charCodeOf(value) {
// `Array.prototype.indexOf` is *extremely* inefficient for arrays which
// are both very sparse and very large (see issue8372.pdf).
const map = this._map;
if (map.length <= 0x10000) {
return map.indexOf(value);
}
for (let charCode in map) {
if (map[charCode] === value) {
return (charCode | 0);
}
}
return -1;
}
getMap() {
return this._map;
}
readCharCode(str, offset, out) {
let c = 0;
const codespaceRanges = this.codespaceRanges;
// 9.7.6.2 CMap Mapping
// The code length is at most 4.
for (let n = 0, nn = codespaceRanges.length; n < nn; n++) {
c = ((c << 8) | str.charCodeAt(offset + n)) >>> 0;
// Check each codespace range to see if it falls within.
const codespaceRange = codespaceRanges[n];
for (let k = 0, kk = codespaceRange.length; k < kk;) {
const low = codespaceRange[k++];
const high = codespaceRange[k++];
if (c >= low && c <= high) {
out.charcode = c;
out.length = n + 1;
return;
}
}
return -1;
},
}
out.charcode = 0;
out.length = 1;
}
getMap() {
return this._map;
},
get length() {
return this._map.length;
}
readCharCode(str, offset, out) {
var c = 0;
var codespaceRanges = this.codespaceRanges;
var codespaceRangesLen = this.codespaceRanges.length;
// 9.7.6.2 CMap Mapping
// The code length is at most 4.
for (var n = 0; n < codespaceRangesLen; n++) {
c = ((c << 8) | str.charCodeAt(offset + n)) >>> 0;
// Check each codespace range to see if it falls within.
var codespaceRange = codespaceRanges[n];
for (var k = 0, kk = codespaceRange.length; k < kk;) {
var low = codespaceRange[k++];
var high = codespaceRange[k++];
if (c >= low && c <= high) {
out.charcode = c;
out.length = n + 1;
return;
}
}
}
out.charcode = 0;
out.length = 1;
},
get length() {
return this._map.length;
},
get isIdentityCMap() {
if (!(this.name === 'Identity-H' || this.name === 'Identity-V')) {
get isIdentityCMap() {
if (!(this.name === 'Identity-H' || this.name === 'Identity-V')) {
return false;
}
if (this._map.length !== 0x10000) {
return false;
}
for (let i = 0; i < 0x10000; i++) {
if (this._map[i] !== i) {
return false;
}
if (this._map.length !== 0x10000) {
return false;
}
for (var i = 0; i < 0x10000; i++) {
if (this._map[i] !== i) {
return false;
}
}
return true;
},
};
return CMap;
})();
}
return true;
}
}
// A special case of CMap, where the _map array implicitly has a length of
// 65536 and each element is equal to its index.
var IdentityCMap = (function IdentityCMapClosure() {
function IdentityCMap(vertical, n) {
CMap.call(this);
class IdentityCMap extends CMap {
constructor(vertical, n) {
super();
this.vertical = vertical;
this.addCodespaceRange(n, 0, 0xffff);
}
Util.inherit(IdentityCMap, CMap, {});
IdentityCMap.prototype = {
addCodespaceRange: CMap.prototype.addCodespaceRange,
mapCidRange(low, high, dstLow) {
unreachable('should not call mapCidRange');
}
mapCidRange(low, high, dstLow) {
unreachable('should not call mapCidRange');
},
mapBfRange(low, high, dstLow) {
unreachable('should not call mapBfRange');
}
mapBfRange(low, high, dstLow) {
unreachable('should not call mapBfRange');
},
mapBfRangeToArray(low, high, array) {
unreachable('should not call mapBfRangeToArray');
}
mapBfRangeToArray(low, high, array) {
unreachable('should not call mapBfRangeToArray');
},
mapOne(src, dst) {
unreachable('should not call mapCidOne');
}
mapOne(src, dst) {
unreachable('should not call mapCidOne');
},
lookup(code) {
return (Number.isInteger(code) && code <= 0xffff) ? code : undefined;
}
lookup(code) {
return (Number.isInteger(code) && code <= 0xffff) ? code : undefined;
},
contains(code) {
return Number.isInteger(code) && code <= 0xffff;
}
contains(code) {
return Number.isInteger(code) && code <= 0xffff;
},
forEach(callback) {
for (let i = 0; i <= 0xffff; i++) {
callback(i, i);
}
}
forEach(callback) {
for (var i = 0; i <= 0xffff; i++) {
callback(i, i);
}
},
charCodeOf(value) {
return (Number.isInteger(value) && value <= 0xffff) ? value : -1;
}
charCodeOf(value) {
return (Number.isInteger(value) && value <= 0xffff) ? value : -1;
},
getMap() {
// Sometimes identity maps must be instantiated, but it's rare.
const map = new Array(0x10000);
for (let i = 0; i <= 0xffff; i++) {
map[i] = i;
}
return map;
}
getMap() {
// Sometimes identity maps must be instantiated, but it's rare.
var map = new Array(0x10000);
for (var i = 0; i <= 0xffff; i++) {
map[i] = i;
}
return map;
},
get length() {
return 0x10000;
}
readCharCode: CMap.prototype.readCharCode,
get length() {
return 0x10000;
},
get isIdentityCMap() {
unreachable('should not access .isIdentityCMap');
},
};
return IdentityCMap;
})();
get isIdentityCMap() {
unreachable('should not access .isIdentityCMap');
}
}
var BinaryCMapReader = (function BinaryCMapReaderClosure() {
function hexToInt(a, size) {

View File

@ -14,7 +14,7 @@
*/
import {
bytesToString, FONT_IDENTITY_MATRIX, FormatError, unreachable, Util, warn
bytesToString, FONT_IDENTITY_MATRIX, FormatError, unreachable, warn
} from '../shared/util';
import { CFFParser } from './cff_parser';
import { getGlyphsUnicode } from './glyphlist';
@ -616,17 +616,22 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
parse(code);
}
var noop = '';
const NOOP = [];
class CompiledFont {
constructor(fontMatrix) {
if (this.constructor === CompiledFont) {
unreachable('Cannot initialize CompiledFont.');
}
this.fontMatrix = fontMatrix;
this.compiledGlyphs = Object.create(null);
this.compiledCharCodeToGlyphId = Object.create(null);
}
function CompiledFont(fontMatrix) {
this.compiledGlyphs = Object.create(null);
this.compiledCharCodeToGlyphId = Object.create(null);
this.fontMatrix = fontMatrix;
}
CompiledFont.prototype = {
getPathJs(unicode) {
var cmap = lookupCmap(this.cmap, unicode);
var fn = this.compiledGlyphs[cmap.glyphId];
const cmap = lookupCmap(this.cmap, unicode);
let fn = this.compiledGlyphs[cmap.glyphId];
if (!fn) {
fn = this.compileGlyph(this.glyphs[cmap.glyphId], cmap.glyphId);
this.compiledGlyphs[cmap.glyphId] = fn;
@ -635,11 +640,11 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
this.compiledCharCodeToGlyphId[cmap.charCode] = cmap.glyphId;
}
return fn;
},
}
compileGlyph(code, glyphId) {
if (!code || code.length === 0 || code[0] === 14) {
return noop;
return NOOP;
}
let fontMatrix = this.fontMatrix;
@ -655,7 +660,7 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
}
}
var cmds = [];
const cmds = [];
cmds.push({ cmd: 'save', });
cmds.push({ cmd: 'transform', args: fontMatrix.slice(), });
cmds.push({ cmd: 'scale', args: ['size', '-size'], });
@ -665,58 +670,56 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
cmds.push({ cmd: 'restore', });
return cmds;
},
}
compileGlyphImpl() {
unreachable('Children classes should implement this.');
},
}
hasBuiltPath(unicode) {
var cmap = lookupCmap(this.cmap, unicode);
const cmap = lookupCmap(this.cmap, unicode);
return (this.compiledGlyphs[cmap.glyphId] !== undefined &&
this.compiledCharCodeToGlyphId[cmap.charCode] !== undefined);
},
};
function TrueTypeCompiled(glyphs, cmap, fontMatrix) {
fontMatrix = fontMatrix || [0.000488, 0, 0, 0.000488, 0, 0];
CompiledFont.call(this, fontMatrix);
this.glyphs = glyphs;
this.cmap = cmap;
}
}
Util.inherit(TrueTypeCompiled, CompiledFont, {
class TrueTypeCompiled extends CompiledFont {
constructor(glyphs, cmap, fontMatrix) {
super(fontMatrix || [0.000488, 0, 0, 0.000488, 0, 0]);
this.glyphs = glyphs;
this.cmap = cmap;
}
compileGlyphImpl(code, cmds) {
compileGlyf(code, cmds, this);
},
});
function Type2Compiled(cffInfo, cmap, fontMatrix, glyphNameMap) {
fontMatrix = fontMatrix || [0.001, 0, 0, 0.001, 0, 0];
CompiledFont.call(this, fontMatrix);
this.glyphs = cffInfo.glyphs;
this.gsubrs = cffInfo.gsubrs || [];
this.subrs = cffInfo.subrs || [];
this.cmap = cmap;
this.glyphNameMap = glyphNameMap || getGlyphsUnicode();
this.gsubrsBias = (this.gsubrs.length < 1240 ?
107 : (this.gsubrs.length < 33900 ? 1131 : 32768));
this.subrsBias = (this.subrs.length < 1240 ?
107 : (this.subrs.length < 33900 ? 1131 : 32768));
this.isCFFCIDFont = cffInfo.isCFFCIDFont;
this.fdSelect = cffInfo.fdSelect;
this.fdArray = cffInfo.fdArray;
}
}
Util.inherit(Type2Compiled, CompiledFont, {
class Type2Compiled extends CompiledFont {
constructor(cffInfo, cmap, fontMatrix, glyphNameMap) {
super(fontMatrix || [0.001, 0, 0, 0.001, 0, 0]);
this.glyphs = cffInfo.glyphs;
this.gsubrs = cffInfo.gsubrs || [];
this.subrs = cffInfo.subrs || [];
this.cmap = cmap;
this.glyphNameMap = glyphNameMap || getGlyphsUnicode();
this.gsubrsBias = (this.gsubrs.length < 1240 ?
107 : (this.gsubrs.length < 33900 ? 1131 : 32768));
this.subrsBias = (this.subrs.length < 1240 ?
107 : (this.subrs.length < 33900 ? 1131 : 32768));
this.isCFFCIDFont = cffInfo.isCFFCIDFont;
this.fdSelect = cffInfo.fdSelect;
this.fdArray = cffInfo.fdArray;
}
compileGlyphImpl(code, cmds, glyphId) {
compileCharString(code, cmds, this, glyphId);
},
});
}
}
return {
create: function FontRendererFactory_create(font, seacAnalysisEnabled) {

View File

@ -16,7 +16,7 @@
import {
bytesToString, createPromiseCapability, createValidAbsoluteUrl, FormatError,
info, InvalidPDFException, isBool, isString, MissingDataException, shadow,
stringToPDFString, stringToUTF8String, unreachable, Util, warn,
stringToPDFString, stringToUTF8String, toRomanNumerals, unreachable, warn,
XRefParseException
} from '../shared/util';
import {
@ -310,7 +310,7 @@ var Catalog = (function CatalogClosure() {
break;
case 'R':
case 'r':
currentLabel = Util.toRoman(currentIndex, style === 'r');
currentLabel = toRomanNumerals(currentIndex, style === 'r');
break;
case 'A':
case 'a':
@ -1573,145 +1573,130 @@ var XRef = (function XRefClosure() {
* see the specification (7.9.6 and 7.9.7) for additional details.
* TODO: implement all the Dict functions and make this more efficient.
*/
var NameOrNumberTree = (function NameOrNumberTreeClosure() {
function NameOrNumberTree(root, xref) {
unreachable('Cannot initialize NameOrNumberTree.');
class NameOrNumberTree {
constructor(root, xref, type) {
if (this.constructor === NameOrNumberTree) {
unreachable('Cannot initialize NameOrNumberTree.');
}
this.root = root;
this.xref = xref;
this._type = type;
}
NameOrNumberTree.prototype = {
getAll: function NameOrNumberTree_getAll() {
var dict = Object.create(null);
if (!this.root) {
return dict;
}
var xref = this.xref;
// Reading Name/Number tree.
var processed = new RefSet();
processed.put(this.root);
var queue = [this.root];
while (queue.length > 0) {
var i, n;
var obj = xref.fetchIfRef(queue.shift());
if (!isDict(obj)) {
continue;
}
if (obj.has('Kids')) {
var kids = obj.get('Kids');
for (i = 0, n = kids.length; i < n; i++) {
var kid = kids[i];
if (processed.has(kid)) {
throw new FormatError(`Duplicate entry in "${this._type}" tree.`);
}
queue.push(kid);
processed.put(kid);
}
continue;
}
var entries = obj.get(this._type);
if (Array.isArray(entries)) {
for (i = 0, n = entries.length; i < n; i += 2) {
dict[xref.fetchIfRef(entries[i])] = xref.fetchIfRef(entries[i + 1]);
}
}
}
getAll() {
const dict = Object.create(null);
if (!this.root) {
return dict;
},
}
const xref = this.xref;
// Reading Name/Number tree.
const processed = new RefSet();
processed.put(this.root);
const queue = [this.root];
while (queue.length > 0) {
const obj = xref.fetchIfRef(queue.shift());
if (!isDict(obj)) {
continue;
}
if (obj.has('Kids')) {
const kids = obj.get('Kids');
for (let i = 0, ii = kids.length; i < ii; i++) {
const kid = kids[i];
if (processed.has(kid)) {
throw new FormatError(`Duplicate entry in "${this._type}" tree.`);
}
queue.push(kid);
processed.put(kid);
}
continue;
}
const entries = obj.get(this._type);
if (Array.isArray(entries)) {
for (let i = 0, ii = entries.length; i < ii; i += 2) {
dict[xref.fetchIfRef(entries[i])] = xref.fetchIfRef(entries[i + 1]);
}
}
}
return dict;
}
get: function NameOrNumberTree_get(key) {
if (!this.root) {
get(key) {
if (!this.root) {
return null;
}
const xref = this.xref;
let kidsOrEntries = xref.fetchIfRef(this.root);
let loopCount = 0;
const MAX_LEVELS = 10;
// Perform a binary search to quickly find the entry that
// contains the key we are looking for.
while (kidsOrEntries.has('Kids')) {
if (++loopCount > MAX_LEVELS) {
warn('Search depth limit reached for "' + this._type + '" tree.');
return null;
}
var xref = this.xref;
var kidsOrEntries = xref.fetchIfRef(this.root);
var loopCount = 0;
var MAX_LEVELS = 10;
var l, r, m;
// Perform a binary search to quickly find the entry that
// contains the key we are looking for.
while (kidsOrEntries.has('Kids')) {
if (++loopCount > MAX_LEVELS) {
warn('Search depth limit reached for "' + this._type + '" tree.');
return null;
}
var kids = kidsOrEntries.get('Kids');
if (!Array.isArray(kids)) {
return null;
}
l = 0;
r = kids.length - 1;
while (l <= r) {
m = (l + r) >> 1;
var kid = xref.fetchIfRef(kids[m]);
var limits = kid.get('Limits');
if (key < xref.fetchIfRef(limits[0])) {
r = m - 1;
} else if (key > xref.fetchIfRef(limits[1])) {
l = m + 1;
} else {
kidsOrEntries = xref.fetchIfRef(kids[m]);
break;
}
}
if (l > r) {
return null;
}
const kids = kidsOrEntries.get('Kids');
if (!Array.isArray(kids)) {
return null;
}
// If we get here, then we have found the right entry. Now go through the
// entries in the dictionary until we find the key we're looking for.
var entries = kidsOrEntries.get(this._type);
if (Array.isArray(entries)) {
// Perform a binary search to reduce the lookup time.
l = 0;
r = entries.length - 2;
while (l <= r) {
// Check only even indices (0, 2, 4, ...) because the
// odd indices contain the actual data.
m = (l + r) & ~1;
var currentKey = xref.fetchIfRef(entries[m]);
if (key < currentKey) {
r = m - 2;
} else if (key > currentKey) {
l = m + 2;
} else {
return xref.fetchIfRef(entries[m + 1]);
}
let l = 0, r = kids.length - 1;
while (l <= r) {
const m = (l + r) >> 1;
const kid = xref.fetchIfRef(kids[m]);
const limits = kid.get('Limits');
if (key < xref.fetchIfRef(limits[0])) {
r = m - 1;
} else if (key > xref.fetchIfRef(limits[1])) {
l = m + 1;
} else {
kidsOrEntries = xref.fetchIfRef(kids[m]);
break;
}
}
return null;
},
};
return NameOrNumberTree;
})();
if (l > r) {
return null;
}
}
var NameTree = (function NameTreeClosure() {
function NameTree(root, xref) {
this.root = root;
this.xref = xref;
this._type = 'Names';
// If we get here, then we have found the right entry. Now go through the
// entries in the dictionary until we find the key we're looking for.
const entries = kidsOrEntries.get(this._type);
if (Array.isArray(entries)) {
// Perform a binary search to reduce the lookup time.
let l = 0, r = entries.length - 2;
while (l <= r) {
// Check only even indices (0, 2, 4, ...) because the
// odd indices contain the actual data.
const m = (l + r) & ~1;
const currentKey = xref.fetchIfRef(entries[m]);
if (key < currentKey) {
r = m - 2;
} else if (key > currentKey) {
l = m + 2;
} else {
return xref.fetchIfRef(entries[m + 1]);
}
}
}
return null;
}
}
Util.inherit(NameTree, NameOrNumberTree, {});
return NameTree;
})();
var NumberTree = (function NumberTreeClosure() {
function NumberTree(root, xref) {
this.root = root;
this.xref = xref;
this._type = 'Nums';
class NameTree extends NameOrNumberTree {
constructor(root, xref) {
super(root, xref, 'Names');
}
}
Util.inherit(NumberTree, NameOrNumberTree, {});
return NumberTree;
})();
class NumberTree extends NameOrNumberTree {
constructor(root, xref) {
super(root, xref, 'Nums');
}
}
/**
* "A PDF file can refer to the contents of another file by using a File

View File

@ -839,53 +839,46 @@ var Util = (function UtilClosure() {
return result;
};
var 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 is false.
* @return {string} The resulting Roman number.
*/
Util.toRoman = function Util_toRoman(number, lowerCase) {
assert(Number.isInteger(number) && number > 0,
'The number should be a positive integer.');
var 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]);
var romanStr = romanBuf.join('');
return (lowerCase ? romanStr.toLowerCase() : romanStr);
};
Util.inherit = function Util_inherit(sub, base, prototype) {
sub.prototype = Object.create(base.prototype);
sub.prototype.constructor = sub;
for (var prop in prototype) {
sub.prototype[prop] = prototype[prop];
}
};
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);
}
var 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,
@ -1033,6 +1026,7 @@ export {
UnexpectedResponseException,
UnknownErrorException,
Util,
toRomanNumerals,
XRefParseException,
FormatError,
arrayByteLength,