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:
commit
b56081c5f8
325
src/core/cmap.js
325
src/core/cmap.js
@ -14,8 +14,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {
|
import {
|
||||||
CMapCompressionType, FormatError, isString, MissingDataException,
|
CMapCompressionType, FormatError, isString, MissingDataException, unreachable,
|
||||||
unreachable, Util, warn
|
warn
|
||||||
} from '../shared/util';
|
} from '../shared/util';
|
||||||
import { isCmd, isEOF, isName, isStream } from './primitives';
|
import { isCmd, isEOF, isName, isStream } from './primitives';
|
||||||
import { Lexer } from './parser';
|
import { Lexer } from './parser';
|
||||||
@ -194,8 +194,8 @@ var BUILT_IN_CMAPS = [
|
|||||||
'WP-Symbol'];
|
'WP-Symbol'];
|
||||||
|
|
||||||
// CMap, not to be confused with TrueType's cmap.
|
// CMap, not to be confused with TrueType's cmap.
|
||||||
var CMap = (function CMapClosure() {
|
class CMap {
|
||||||
function CMap(builtInCMap) {
|
constructor(builtInCMap = false) {
|
||||||
// Codespace ranges are stored as follows:
|
// Codespace ranges are stored as follows:
|
||||||
// [[1BytePairs], [2BytePairs], [3BytePairs], [4BytePairs]]
|
// [[1BytePairs], [2BytePairs], [3BytePairs], [4BytePairs]]
|
||||||
// where nBytePairs are ranges e.g. [low1, high1, low2, high2, ...]
|
// where nBytePairs are ranges e.g. [low1, high1, low2, high2, ...]
|
||||||
@ -211,204 +211,193 @@ var CMap = (function CMapClosure() {
|
|||||||
this.useCMap = null;
|
this.useCMap = null;
|
||||||
this.builtInCMap = builtInCMap;
|
this.builtInCMap = builtInCMap;
|
||||||
}
|
}
|
||||||
CMap.prototype = {
|
|
||||||
addCodespaceRange(n, low, high) {
|
|
||||||
this.codespaceRanges[n - 1].push(low, high);
|
|
||||||
this.numCodespaceRanges++;
|
|
||||||
},
|
|
||||||
|
|
||||||
mapCidRange(low, high, dstLow) {
|
addCodespaceRange(n, low, high) {
|
||||||
while (low <= high) {
|
this.codespaceRanges[n - 1].push(low, high);
|
||||||
this._map[low++] = dstLow++;
|
this.numCodespaceRanges++;
|
||||||
}
|
}
|
||||||
},
|
|
||||||
|
|
||||||
mapBfRange(low, high, dstLow) {
|
mapCidRange(low, high, dstLow) {
|
||||||
var lastByte = dstLow.length - 1;
|
while (low <= high) {
|
||||||
while (low <= high) {
|
this._map[low++] = dstLow++;
|
||||||
this._map[low++] = dstLow;
|
}
|
||||||
// Only the last byte has to be incremented.
|
}
|
||||||
dstLow = dstLow.substr(0, lastByte) +
|
|
||||||
String.fromCharCode(dstLow.charCodeAt(lastByte) + 1);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
mapBfRangeToArray(low, high, array) {
|
mapBfRange(low, high, dstLow) {
|
||||||
var i = 0, ii = array.length;
|
var lastByte = dstLow.length - 1;
|
||||||
while (low <= high && i < ii) {
|
while (low <= high) {
|
||||||
this._map[low] = array[i++];
|
this._map[low++] = dstLow;
|
||||||
++low;
|
// 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.
|
mapBfRangeToArray(low, high, array) {
|
||||||
mapOne(src, dst) {
|
let i = 0, ii = array.length;
|
||||||
this._map[src] = dst;
|
while (low <= high && i < ii) {
|
||||||
},
|
this._map[low] = array[i++];
|
||||||
|
++low;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
lookup(code) {
|
// This is used for both bf and cid chars.
|
||||||
return this._map[code];
|
mapOne(src, dst) {
|
||||||
},
|
this._map[src] = dst;
|
||||||
|
}
|
||||||
|
|
||||||
contains(code) {
|
lookup(code) {
|
||||||
return this._map[code] !== undefined;
|
return this._map[code];
|
||||||
},
|
}
|
||||||
|
|
||||||
forEach(callback) {
|
contains(code) {
|
||||||
// Most maps have fewer than 65536 entries, and for those we use normal
|
return this._map[code] !== undefined;
|
||||||
// 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
|
forEach(callback) {
|
||||||
// it does avoid iterating over every undefined entry.
|
// Most maps have fewer than 65536 entries, and for those we use normal
|
||||||
let map = this._map;
|
// array iteration. But really sparse tables are possible -- e.g. with
|
||||||
let length = map.length;
|
// indices in the *billions*. For such tables we use for..in, which isn't
|
||||||
if (length <= 0x10000) {
|
// ideal because it stringifies the indices for all present elements, but
|
||||||
for (let i = 0; i < length; i++) {
|
// it does avoid iterating over every undefined entry.
|
||||||
if (map[i] !== undefined) {
|
let map = this._map;
|
||||||
callback(i, map[i]);
|
let length = map.length;
|
||||||
}
|
if (length <= 0x10000) {
|
||||||
}
|
for (let i = 0; i < length; i++) {
|
||||||
} else {
|
if (map[i] !== undefined) {
|
||||||
for (let i in map) {
|
|
||||||
callback(i, map[i]);
|
callback(i, map[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
} else {
|
||||||
|
for (let i in map) {
|
||||||
charCodeOf(value) {
|
callback(i, map[i]);
|
||||||
// `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);
|
|
||||||
}
|
}
|
||||||
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() {
|
get length() {
|
||||||
return this._map;
|
return this._map.length;
|
||||||
},
|
}
|
||||||
|
|
||||||
readCharCode(str, offset, out) {
|
get isIdentityCMap() {
|
||||||
var c = 0;
|
if (!(this.name === 'Identity-H' || this.name === 'Identity-V')) {
|
||||||
var codespaceRanges = this.codespaceRanges;
|
return false;
|
||||||
var codespaceRangesLen = this.codespaceRanges.length;
|
}
|
||||||
// 9.7.6.2 CMap Mapping
|
if (this._map.length !== 0x10000) {
|
||||||
// The code length is at most 4.
|
return false;
|
||||||
for (var n = 0; n < codespaceRangesLen; n++) {
|
}
|
||||||
c = ((c << 8) | str.charCodeAt(offset + n)) >>> 0;
|
for (let i = 0; i < 0x10000; i++) {
|
||||||
// Check each codespace range to see if it falls within.
|
if (this._map[i] !== i) {
|
||||||
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')) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (this._map.length !== 0x10000) {
|
}
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
for (var i = 0; i < 0x10000; i++) {
|
}
|
||||||
if (this._map[i] !== i) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
return CMap;
|
|
||||||
})();
|
|
||||||
|
|
||||||
// A special case of CMap, where the _map array implicitly has a length of
|
// A special case of CMap, where the _map array implicitly has a length of
|
||||||
// 65536 and each element is equal to its index.
|
// 65536 and each element is equal to its index.
|
||||||
var IdentityCMap = (function IdentityCMapClosure() {
|
class IdentityCMap extends CMap {
|
||||||
function IdentityCMap(vertical, n) {
|
constructor(vertical, n) {
|
||||||
CMap.call(this);
|
super();
|
||||||
|
|
||||||
this.vertical = vertical;
|
this.vertical = vertical;
|
||||||
this.addCodespaceRange(n, 0, 0xffff);
|
this.addCodespaceRange(n, 0, 0xffff);
|
||||||
}
|
}
|
||||||
Util.inherit(IdentityCMap, CMap, {});
|
|
||||||
|
|
||||||
IdentityCMap.prototype = {
|
mapCidRange(low, high, dstLow) {
|
||||||
addCodespaceRange: CMap.prototype.addCodespaceRange,
|
unreachable('should not call mapCidRange');
|
||||||
|
}
|
||||||
|
|
||||||
mapCidRange(low, high, dstLow) {
|
mapBfRange(low, high, dstLow) {
|
||||||
unreachable('should not call mapCidRange');
|
unreachable('should not call mapBfRange');
|
||||||
},
|
}
|
||||||
|
|
||||||
mapBfRange(low, high, dstLow) {
|
mapBfRangeToArray(low, high, array) {
|
||||||
unreachable('should not call mapBfRange');
|
unreachable('should not call mapBfRangeToArray');
|
||||||
},
|
}
|
||||||
|
|
||||||
mapBfRangeToArray(low, high, array) {
|
mapOne(src, dst) {
|
||||||
unreachable('should not call mapBfRangeToArray');
|
unreachable('should not call mapCidOne');
|
||||||
},
|
}
|
||||||
|
|
||||||
mapOne(src, dst) {
|
lookup(code) {
|
||||||
unreachable('should not call mapCidOne');
|
return (Number.isInteger(code) && code <= 0xffff) ? code : undefined;
|
||||||
},
|
}
|
||||||
|
|
||||||
lookup(code) {
|
contains(code) {
|
||||||
return (Number.isInteger(code) && code <= 0xffff) ? code : undefined;
|
return Number.isInteger(code) && code <= 0xffff;
|
||||||
},
|
}
|
||||||
|
|
||||||
contains(code) {
|
forEach(callback) {
|
||||||
return Number.isInteger(code) && code <= 0xffff;
|
for (let i = 0; i <= 0xffff; i++) {
|
||||||
},
|
callback(i, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
forEach(callback) {
|
charCodeOf(value) {
|
||||||
for (var i = 0; i <= 0xffff; i++) {
|
return (Number.isInteger(value) && value <= 0xffff) ? value : -1;
|
||||||
callback(i, i);
|
}
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
charCodeOf(value) {
|
getMap() {
|
||||||
return (Number.isInteger(value) && value <= 0xffff) ? value : -1;
|
// 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() {
|
get length() {
|
||||||
// Sometimes identity maps must be instantiated, but it's rare.
|
return 0x10000;
|
||||||
var map = new Array(0x10000);
|
}
|
||||||
for (var i = 0; i <= 0xffff; i++) {
|
|
||||||
map[i] = i;
|
|
||||||
}
|
|
||||||
return map;
|
|
||||||
},
|
|
||||||
|
|
||||||
readCharCode: CMap.prototype.readCharCode,
|
get isIdentityCMap() {
|
||||||
|
unreachable('should not access .isIdentityCMap');
|
||||||
get length() {
|
}
|
||||||
return 0x10000;
|
}
|
||||||
},
|
|
||||||
|
|
||||||
get isIdentityCMap() {
|
|
||||||
unreachable('should not access .isIdentityCMap');
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
return IdentityCMap;
|
|
||||||
})();
|
|
||||||
|
|
||||||
var BinaryCMapReader = (function BinaryCMapReaderClosure() {
|
var BinaryCMapReader = (function BinaryCMapReaderClosure() {
|
||||||
function hexToInt(a, size) {
|
function hexToInt(a, size) {
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {
|
import {
|
||||||
bytesToString, FONT_IDENTITY_MATRIX, FormatError, unreachable, Util, warn
|
bytesToString, FONT_IDENTITY_MATRIX, FormatError, unreachable, warn
|
||||||
} from '../shared/util';
|
} from '../shared/util';
|
||||||
import { CFFParser } from './cff_parser';
|
import { CFFParser } from './cff_parser';
|
||||||
import { getGlyphsUnicode } from './glyphlist';
|
import { getGlyphsUnicode } from './glyphlist';
|
||||||
@ -616,17 +616,22 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
|
|||||||
parse(code);
|
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) {
|
getPathJs(unicode) {
|
||||||
var cmap = lookupCmap(this.cmap, unicode);
|
const cmap = lookupCmap(this.cmap, unicode);
|
||||||
var fn = this.compiledGlyphs[cmap.glyphId];
|
let fn = this.compiledGlyphs[cmap.glyphId];
|
||||||
if (!fn) {
|
if (!fn) {
|
||||||
fn = this.compileGlyph(this.glyphs[cmap.glyphId], cmap.glyphId);
|
fn = this.compileGlyph(this.glyphs[cmap.glyphId], cmap.glyphId);
|
||||||
this.compiledGlyphs[cmap.glyphId] = fn;
|
this.compiledGlyphs[cmap.glyphId] = fn;
|
||||||
@ -635,11 +640,11 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
|
|||||||
this.compiledCharCodeToGlyphId[cmap.charCode] = cmap.glyphId;
|
this.compiledCharCodeToGlyphId[cmap.charCode] = cmap.glyphId;
|
||||||
}
|
}
|
||||||
return fn;
|
return fn;
|
||||||
},
|
}
|
||||||
|
|
||||||
compileGlyph(code, glyphId) {
|
compileGlyph(code, glyphId) {
|
||||||
if (!code || code.length === 0 || code[0] === 14) {
|
if (!code || code.length === 0 || code[0] === 14) {
|
||||||
return noop;
|
return NOOP;
|
||||||
}
|
}
|
||||||
|
|
||||||
let fontMatrix = this.fontMatrix;
|
let fontMatrix = this.fontMatrix;
|
||||||
@ -655,7 +660,7 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var cmds = [];
|
const cmds = [];
|
||||||
cmds.push({ cmd: 'save', });
|
cmds.push({ cmd: 'save', });
|
||||||
cmds.push({ cmd: 'transform', args: fontMatrix.slice(), });
|
cmds.push({ cmd: 'transform', args: fontMatrix.slice(), });
|
||||||
cmds.push({ cmd: 'scale', args: ['size', '-size'], });
|
cmds.push({ cmd: 'scale', args: ['size', '-size'], });
|
||||||
@ -665,58 +670,56 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
|
|||||||
cmds.push({ cmd: 'restore', });
|
cmds.push({ cmd: 'restore', });
|
||||||
|
|
||||||
return cmds;
|
return cmds;
|
||||||
},
|
}
|
||||||
|
|
||||||
compileGlyphImpl() {
|
compileGlyphImpl() {
|
||||||
unreachable('Children classes should implement this.');
|
unreachable('Children classes should implement this.');
|
||||||
},
|
}
|
||||||
|
|
||||||
hasBuiltPath(unicode) {
|
hasBuiltPath(unicode) {
|
||||||
var cmap = lookupCmap(this.cmap, unicode);
|
const cmap = lookupCmap(this.cmap, unicode);
|
||||||
return (this.compiledGlyphs[cmap.glyphId] !== undefined &&
|
return (this.compiledGlyphs[cmap.glyphId] !== undefined &&
|
||||||
this.compiledCharCodeToGlyphId[cmap.charCode] !== 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) {
|
compileGlyphImpl(code, cmds) {
|
||||||
compileGlyf(code, cmds, this);
|
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) {
|
compileGlyphImpl(code, cmds, glyphId) {
|
||||||
compileCharString(code, cmds, this, glyphId);
|
compileCharString(code, cmds, this, glyphId);
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
create: function FontRendererFactory_create(font, seacAnalysisEnabled) {
|
create: function FontRendererFactory_create(font, seacAnalysisEnabled) {
|
||||||
|
235
src/core/obj.js
235
src/core/obj.js
@ -16,7 +16,7 @@
|
|||||||
import {
|
import {
|
||||||
bytesToString, createPromiseCapability, createValidAbsoluteUrl, FormatError,
|
bytesToString, createPromiseCapability, createValidAbsoluteUrl, FormatError,
|
||||||
info, InvalidPDFException, isBool, isString, MissingDataException, shadow,
|
info, InvalidPDFException, isBool, isString, MissingDataException, shadow,
|
||||||
stringToPDFString, stringToUTF8String, unreachable, Util, warn,
|
stringToPDFString, stringToUTF8String, toRomanNumerals, unreachable, warn,
|
||||||
XRefParseException
|
XRefParseException
|
||||||
} from '../shared/util';
|
} from '../shared/util';
|
||||||
import {
|
import {
|
||||||
@ -310,7 +310,7 @@ var Catalog = (function CatalogClosure() {
|
|||||||
break;
|
break;
|
||||||
case 'R':
|
case 'R':
|
||||||
case 'r':
|
case 'r':
|
||||||
currentLabel = Util.toRoman(currentIndex, style === 'r');
|
currentLabel = toRomanNumerals(currentIndex, style === 'r');
|
||||||
break;
|
break;
|
||||||
case 'A':
|
case 'A':
|
||||||
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.
|
* see the specification (7.9.6 and 7.9.7) for additional details.
|
||||||
* TODO: implement all the Dict functions and make this more efficient.
|
* TODO: implement all the Dict functions and make this more efficient.
|
||||||
*/
|
*/
|
||||||
var NameOrNumberTree = (function NameOrNumberTreeClosure() {
|
class NameOrNumberTree {
|
||||||
function NameOrNumberTree(root, xref) {
|
constructor(root, xref, type) {
|
||||||
unreachable('Cannot initialize NameOrNumberTree.');
|
if (this.constructor === NameOrNumberTree) {
|
||||||
|
unreachable('Cannot initialize NameOrNumberTree.');
|
||||||
|
}
|
||||||
|
this.root = root;
|
||||||
|
this.xref = xref;
|
||||||
|
this._type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
NameOrNumberTree.prototype = {
|
getAll() {
|
||||||
getAll: function NameOrNumberTree_getAll() {
|
const dict = Object.create(null);
|
||||||
var dict = Object.create(null);
|
if (!this.root) {
|
||||||
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]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return dict;
|
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) {
|
get(key) {
|
||||||
if (!this.root) {
|
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;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
var xref = this.xref;
|
const kids = kidsOrEntries.get('Kids');
|
||||||
var kidsOrEntries = xref.fetchIfRef(this.root);
|
if (!Array.isArray(kids)) {
|
||||||
var loopCount = 0;
|
return null;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we get here, then we have found the right entry. Now go through the
|
let l = 0, r = kids.length - 1;
|
||||||
// entries in the dictionary until we find the key we're looking for.
|
while (l <= r) {
|
||||||
var entries = kidsOrEntries.get(this._type);
|
const m = (l + r) >> 1;
|
||||||
if (Array.isArray(entries)) {
|
const kid = xref.fetchIfRef(kids[m]);
|
||||||
// Perform a binary search to reduce the lookup time.
|
const limits = kid.get('Limits');
|
||||||
l = 0;
|
|
||||||
r = entries.length - 2;
|
if (key < xref.fetchIfRef(limits[0])) {
|
||||||
while (l <= r) {
|
r = m - 1;
|
||||||
// Check only even indices (0, 2, 4, ...) because the
|
} else if (key > xref.fetchIfRef(limits[1])) {
|
||||||
// odd indices contain the actual data.
|
l = m + 1;
|
||||||
m = (l + r) & ~1;
|
} else {
|
||||||
var currentKey = xref.fetchIfRef(entries[m]);
|
kidsOrEntries = xref.fetchIfRef(kids[m]);
|
||||||
if (key < currentKey) {
|
break;
|
||||||
r = m - 2;
|
|
||||||
} else if (key > currentKey) {
|
|
||||||
l = m + 2;
|
|
||||||
} else {
|
|
||||||
return xref.fetchIfRef(entries[m + 1]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
if (l > r) {
|
||||||
},
|
return null;
|
||||||
};
|
}
|
||||||
return NameOrNumberTree;
|
}
|
||||||
})();
|
|
||||||
|
|
||||||
var NameTree = (function NameTreeClosure() {
|
// If we get here, then we have found the right entry. Now go through the
|
||||||
function NameTree(root, xref) {
|
// entries in the dictionary until we find the key we're looking for.
|
||||||
this.root = root;
|
const entries = kidsOrEntries.get(this._type);
|
||||||
this.xref = xref;
|
if (Array.isArray(entries)) {
|
||||||
this._type = 'Names';
|
// 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, {});
|
class NameTree extends NameOrNumberTree {
|
||||||
|
constructor(root, xref) {
|
||||||
return NameTree;
|
super(root, xref, 'Names');
|
||||||
})();
|
|
||||||
|
|
||||||
var NumberTree = (function NumberTreeClosure() {
|
|
||||||
function NumberTree(root, xref) {
|
|
||||||
this.root = root;
|
|
||||||
this.xref = xref;
|
|
||||||
this._type = 'Nums';
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Util.inherit(NumberTree, NameOrNumberTree, {});
|
class NumberTree extends NameOrNumberTree {
|
||||||
|
constructor(root, xref) {
|
||||||
return NumberTree;
|
super(root, xref, 'Nums');
|
||||||
})();
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* "A PDF file can refer to the contents of another file by using a File
|
* "A PDF file can refer to the contents of another file by using a File
|
||||||
|
@ -839,53 +839,46 @@ var Util = (function UtilClosure() {
|
|||||||
return result;
|
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;
|
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 = [
|
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,
|
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,
|
0x2D8, 0x2C7, 0x2C6, 0x2D9, 0x2DD, 0x2DB, 0x2DA, 0x2DC, 0, 0, 0, 0, 0, 0, 0,
|
||||||
@ -1033,6 +1026,7 @@ export {
|
|||||||
UnexpectedResponseException,
|
UnexpectedResponseException,
|
||||||
UnknownErrorException,
|
UnknownErrorException,
|
||||||
Util,
|
Util,
|
||||||
|
toRomanNumerals,
|
||||||
XRefParseException,
|
XRefParseException,
|
||||||
FormatError,
|
FormatError,
|
||||||
arrayByteLength,
|
arrayByteLength,
|
||||||
|
Loading…
Reference in New Issue
Block a user