1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 | "use strict";
|
23 |
|
24 | Object.defineProperty(exports, "__esModule", {
|
25 | value: true
|
26 | });
|
27 | exports.getFontType = getFontType;
|
28 | exports.IdentityToUnicodeMap = exports.ToUnicodeMap = exports.FontFlags = exports.Font = exports.ErrorFont = exports.SEAC_ANALYSIS_ENABLED = void 0;
|
29 |
|
30 | var _util = require("../shared/util");
|
31 |
|
32 | var _cff_parser = require("./cff_parser");
|
33 |
|
34 | var _glyphlist = require("./glyphlist");
|
35 |
|
36 | var _encodings = require("./encodings");
|
37 |
|
38 | var _standard_fonts = require("./standard_fonts");
|
39 |
|
40 | var _unicode = require("./unicode");
|
41 |
|
42 | var _font_renderer = require("./font_renderer");
|
43 |
|
44 | var _cmap = require("./cmap");
|
45 |
|
46 | var _stream = require("./stream");
|
47 |
|
48 | var _type1_parser = require("./type1_parser");
|
49 |
|
50 | function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); }
|
51 |
|
52 | function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); }
|
53 |
|
54 | function _iterableToArrayLimit(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }
|
55 |
|
56 | function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
|
57 |
|
58 | var PRIVATE_USE_AREAS = [[0xE000, 0xF8FF], [0x100000, 0x10FFFD]];
|
59 | var PDF_GLYPH_SPACE_UNITS = 1000;
|
60 | var SEAC_ANALYSIS_ENABLED = true;
|
61 | exports.SEAC_ANALYSIS_ENABLED = SEAC_ANALYSIS_ENABLED;
|
62 | var FontFlags = {
|
63 | FixedPitch: 1,
|
64 | Serif: 2,
|
65 | Symbolic: 4,
|
66 | Script: 8,
|
67 | Nonsymbolic: 32,
|
68 | Italic: 64,
|
69 | AllCap: 65536,
|
70 | SmallCap: 131072,
|
71 | ForceBold: 262144
|
72 | };
|
73 | exports.FontFlags = FontFlags;
|
74 | var MacStandardGlyphOrdering = ['.notdef', '.null', 'nonmarkingreturn', 'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent', 'ampersand', 'quotesingle', 'parenleft', 'parenright', 'asterisk', 'plus', 'comma', 'hyphen', 'period', 'slash', 'zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon', 'less', 'equal', 'greater', 'question', 'at', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'bracketleft', 'backslash', 'bracketright', 'asciicircum', 'underscore', 'grave', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'braceleft', 'bar', 'braceright', 'asciitilde', 'Adieresis', 'Aring', 'Ccedilla', 'Eacute', 'Ntilde', 'Odieresis', 'Udieresis', 'aacute', 'agrave', 'acircumflex', 'adieresis', 'atilde', 'aring', 'ccedilla', 'eacute', 'egrave', 'ecircumflex', 'edieresis', 'iacute', 'igrave', 'icircumflex', 'idieresis', 'ntilde', 'oacute', 'ograve', 'ocircumflex', 'odieresis', 'otilde', 'uacute', 'ugrave', 'ucircumflex', 'udieresis', 'dagger', 'degree', 'cent', 'sterling', 'section', 'bullet', 'paragraph', 'germandbls', 'registered', 'copyright', 'trademark', 'acute', 'dieresis', 'notequal', 'AE', 'Oslash', 'infinity', 'plusminus', 'lessequal', 'greaterequal', 'yen', 'mu', 'partialdiff', 'summation', 'product', 'pi', 'integral', 'ordfeminine', 'ordmasculine', 'Omega', 'ae', 'oslash', 'questiondown', 'exclamdown', 'logicalnot', 'radical', 'florin', 'approxequal', 'Delta', 'guillemotleft', 'guillemotright', 'ellipsis', 'nonbreakingspace', 'Agrave', 'Atilde', 'Otilde', 'OE', 'oe', 'endash', 'emdash', 'quotedblleft', 'quotedblright', 'quoteleft', 'quoteright', 'divide', 'lozenge', 'ydieresis', 'Ydieresis', 'fraction', 'currency', 'guilsinglleft', 'guilsinglright', 'fi', 'fl', 'daggerdbl', 'periodcentered', 'quotesinglbase', 'quotedblbase', 'perthousand', 'Acircumflex', 'Ecircumflex', 'Aacute', 'Edieresis', 'Egrave', 'Iacute', 'Icircumflex', 'Idieresis', 'Igrave', 'Oacute', 'Ocircumflex', 'apple', 'Ograve', 'Uacute', 'Ucircumflex', 'Ugrave', 'dotlessi', 'circumflex', 'tilde', 'macron', 'breve', 'dotaccent', 'ring', 'cedilla', 'hungarumlaut', 'ogonek', 'caron', 'Lslash', 'lslash', 'Scaron', 'scaron', 'Zcaron', 'zcaron', 'brokenbar', 'Eth', 'eth', 'Yacute', 'yacute', 'Thorn', 'thorn', 'minus', 'multiply', 'onesuperior', 'twosuperior', 'threesuperior', 'onehalf', 'onequarter', 'threequarters', 'franc', 'Gbreve', 'gbreve', 'Idotaccent', 'Scedilla', 'scedilla', 'Cacute', 'cacute', 'Ccaron', 'ccaron', 'dcroat'];
|
75 |
|
76 | function adjustWidths(properties) {
|
77 | if (!properties.fontMatrix) {
|
78 | return;
|
79 | }
|
80 |
|
81 | if (properties.fontMatrix[0] === _util.FONT_IDENTITY_MATRIX[0]) {
|
82 | return;
|
83 | }
|
84 |
|
85 | var scale = 0.001 / properties.fontMatrix[0];
|
86 | var glyphsWidths = properties.widths;
|
87 |
|
88 | for (var glyph in glyphsWidths) {
|
89 | glyphsWidths[glyph] *= scale;
|
90 | }
|
91 |
|
92 | properties.defaultWidth *= scale;
|
93 | }
|
94 |
|
95 | function adjustToUnicode(properties, builtInEncoding) {
|
96 | if (properties.hasIncludedToUnicodeMap) {
|
97 | return;
|
98 | }
|
99 |
|
100 | if (properties.hasEncoding) {
|
101 | return;
|
102 | }
|
103 |
|
104 | if (builtInEncoding === properties.defaultEncoding) {
|
105 | return;
|
106 | }
|
107 |
|
108 | if (properties.toUnicode instanceof IdentityToUnicodeMap) {
|
109 | return;
|
110 | }
|
111 |
|
112 | var toUnicode = [],
|
113 | glyphsUnicodeMap = (0, _glyphlist.getGlyphsUnicode)();
|
114 |
|
115 | for (var charCode in builtInEncoding) {
|
116 | var glyphName = builtInEncoding[charCode];
|
117 | var unicode = (0, _unicode.getUnicodeForGlyph)(glyphName, glyphsUnicodeMap);
|
118 |
|
119 | if (unicode !== -1) {
|
120 | toUnicode[charCode] = String.fromCharCode(unicode);
|
121 | }
|
122 | }
|
123 |
|
124 | properties.toUnicode.amend(toUnicode);
|
125 | }
|
126 |
|
127 | function getFontType(type, subtype) {
|
128 | switch (type) {
|
129 | case 'Type1':
|
130 | return subtype === 'Type1C' ? _util.FontType.TYPE1C : _util.FontType.TYPE1;
|
131 |
|
132 | case 'CIDFontType0':
|
133 | return subtype === 'CIDFontType0C' ? _util.FontType.CIDFONTTYPE0C : _util.FontType.CIDFONTTYPE0;
|
134 |
|
135 | case 'OpenType':
|
136 | return _util.FontType.OPENTYPE;
|
137 |
|
138 | case 'TrueType':
|
139 | return _util.FontType.TRUETYPE;
|
140 |
|
141 | case 'CIDFontType2':
|
142 | return _util.FontType.CIDFONTTYPE2;
|
143 |
|
144 | case 'MMType1':
|
145 | return _util.FontType.MMTYPE1;
|
146 |
|
147 | case 'Type0':
|
148 | return _util.FontType.TYPE0;
|
149 |
|
150 | default:
|
151 | return _util.FontType.UNKNOWN;
|
152 | }
|
153 | }
|
154 |
|
155 | function recoverGlyphName(name, glyphsUnicodeMap) {
|
156 | if (glyphsUnicodeMap[name] !== undefined) {
|
157 | return name;
|
158 | }
|
159 |
|
160 | var unicode = (0, _unicode.getUnicodeForGlyph)(name, glyphsUnicodeMap);
|
161 |
|
162 | if (unicode !== -1) {
|
163 | for (var key in glyphsUnicodeMap) {
|
164 | if (glyphsUnicodeMap[key] === unicode) {
|
165 | return key;
|
166 | }
|
167 | }
|
168 | }
|
169 |
|
170 | (0, _util.info)('Unable to recover a standard glyph name for: ' + name);
|
171 | return name;
|
172 | }
|
173 |
|
174 | var Glyph = function GlyphClosure() {
|
175 | function Glyph(fontChar, unicode, accent, width, vmetric, operatorListId, isSpace, isInFont) {
|
176 | this.fontChar = fontChar;
|
177 | this.unicode = unicode;
|
178 | this.accent = accent;
|
179 | this.width = width;
|
180 | this.vmetric = vmetric;
|
181 | this.operatorListId = operatorListId;
|
182 | this.isSpace = isSpace;
|
183 | this.isInFont = isInFont;
|
184 | }
|
185 |
|
186 | Glyph.prototype.matchesForCache = function (fontChar, unicode, accent, width, vmetric, operatorListId, isSpace, isInFont) {
|
187 | return this.fontChar === fontChar && this.unicode === unicode && this.accent === accent && this.width === width && this.vmetric === vmetric && this.operatorListId === operatorListId && this.isSpace === isSpace && this.isInFont === isInFont;
|
188 | };
|
189 |
|
190 | return Glyph;
|
191 | }();
|
192 |
|
193 | var ToUnicodeMap = function ToUnicodeMapClosure() {
|
194 | function ToUnicodeMap() {
|
195 | var cmap = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
|
196 | this._map = cmap;
|
197 | }
|
198 |
|
199 | ToUnicodeMap.prototype = {
|
200 | get length() {
|
201 | return this._map.length;
|
202 | },
|
203 |
|
204 | forEach: function forEach(callback) {
|
205 | for (var charCode in this._map) {
|
206 | callback(charCode, this._map[charCode].charCodeAt(0));
|
207 | }
|
208 | },
|
209 | has: function has(i) {
|
210 | return this._map[i] !== undefined;
|
211 | },
|
212 | get: function get(i) {
|
213 | return this._map[i];
|
214 | },
|
215 | charCodeOf: function charCodeOf(value) {
|
216 | var map = this._map;
|
217 |
|
218 | if (map.length <= 0x10000) {
|
219 | return map.indexOf(value);
|
220 | }
|
221 |
|
222 | for (var charCode in map) {
|
223 | if (map[charCode] === value) {
|
224 | return charCode | 0;
|
225 | }
|
226 | }
|
227 |
|
228 | return -1;
|
229 | },
|
230 | amend: function amend(map) {
|
231 | for (var charCode in map) {
|
232 | this._map[charCode] = map[charCode];
|
233 | }
|
234 | }
|
235 | };
|
236 | return ToUnicodeMap;
|
237 | }();
|
238 |
|
239 | exports.ToUnicodeMap = ToUnicodeMap;
|
240 |
|
241 | var IdentityToUnicodeMap = function IdentityToUnicodeMapClosure() {
|
242 | function IdentityToUnicodeMap(firstChar, lastChar) {
|
243 | this.firstChar = firstChar;
|
244 | this.lastChar = lastChar;
|
245 | }
|
246 |
|
247 | IdentityToUnicodeMap.prototype = {
|
248 | get length() {
|
249 | return this.lastChar + 1 - this.firstChar;
|
250 | },
|
251 |
|
252 | forEach: function forEach(callback) {
|
253 | for (var i = this.firstChar, ii = this.lastChar; i <= ii; i++) {
|
254 | callback(i, i);
|
255 | }
|
256 | },
|
257 | has: function has(i) {
|
258 | return this.firstChar <= i && i <= this.lastChar;
|
259 | },
|
260 | get: function get(i) {
|
261 | if (this.firstChar <= i && i <= this.lastChar) {
|
262 | return String.fromCharCode(i);
|
263 | }
|
264 |
|
265 | return undefined;
|
266 | },
|
267 | charCodeOf: function charCodeOf(v) {
|
268 | return Number.isInteger(v) && v >= this.firstChar && v <= this.lastChar ? v : -1;
|
269 | },
|
270 | amend: function amend(map) {
|
271 | (0, _util.unreachable)('Should not call amend()');
|
272 | }
|
273 | };
|
274 | return IdentityToUnicodeMap;
|
275 | }();
|
276 |
|
277 | exports.IdentityToUnicodeMap = IdentityToUnicodeMap;
|
278 |
|
279 | var OpenTypeFileBuilder = function OpenTypeFileBuilderClosure() {
|
280 | function writeInt16(dest, offset, num) {
|
281 | dest[offset] = num >> 8 & 0xFF;
|
282 | dest[offset + 1] = num & 0xFF;
|
283 | }
|
284 |
|
285 | function writeInt32(dest, offset, num) {
|
286 | dest[offset] = num >> 24 & 0xFF;
|
287 | dest[offset + 1] = num >> 16 & 0xFF;
|
288 | dest[offset + 2] = num >> 8 & 0xFF;
|
289 | dest[offset + 3] = num & 0xFF;
|
290 | }
|
291 |
|
292 | function writeData(dest, offset, data) {
|
293 | var i, ii;
|
294 |
|
295 | if (data instanceof Uint8Array) {
|
296 | dest.set(data, offset);
|
297 | } else if (typeof data === 'string') {
|
298 | for (i = 0, ii = data.length; i < ii; i++) {
|
299 | dest[offset++] = data.charCodeAt(i) & 0xFF;
|
300 | }
|
301 | } else {
|
302 | for (i = 0, ii = data.length; i < ii; i++) {
|
303 | dest[offset++] = data[i] & 0xFF;
|
304 | }
|
305 | }
|
306 | }
|
307 |
|
308 | function OpenTypeFileBuilder(sfnt) {
|
309 | this.sfnt = sfnt;
|
310 | this.tables = Object.create(null);
|
311 | }
|
312 |
|
313 | OpenTypeFileBuilder.getSearchParams = function OpenTypeFileBuilder_getSearchParams(entriesCount, entrySize) {
|
314 | var maxPower2 = 1,
|
315 | log2 = 0;
|
316 |
|
317 | while ((maxPower2 ^ entriesCount) > maxPower2) {
|
318 | maxPower2 <<= 1;
|
319 | log2++;
|
320 | }
|
321 |
|
322 | var searchRange = maxPower2 * entrySize;
|
323 | return {
|
324 | range: searchRange,
|
325 | entry: log2,
|
326 | rangeShift: entrySize * entriesCount - searchRange
|
327 | };
|
328 | };
|
329 |
|
330 | var OTF_HEADER_SIZE = 12;
|
331 | var OTF_TABLE_ENTRY_SIZE = 16;
|
332 | OpenTypeFileBuilder.prototype = {
|
333 | toArray: function OpenTypeFileBuilder_toArray() {
|
334 | var sfnt = this.sfnt;
|
335 | var tables = this.tables;
|
336 | var tablesNames = Object.keys(tables);
|
337 | tablesNames.sort();
|
338 | var numTables = tablesNames.length;
|
339 | var i, j, jj, table, tableName;
|
340 | var offset = OTF_HEADER_SIZE + numTables * OTF_TABLE_ENTRY_SIZE;
|
341 | var tableOffsets = [offset];
|
342 |
|
343 | for (i = 0; i < numTables; i++) {
|
344 | table = tables[tablesNames[i]];
|
345 | var paddedLength = (table.length + 3 & ~3) >>> 0;
|
346 | offset += paddedLength;
|
347 | tableOffsets.push(offset);
|
348 | }
|
349 |
|
350 | var file = new Uint8Array(offset);
|
351 |
|
352 | for (i = 0; i < numTables; i++) {
|
353 | table = tables[tablesNames[i]];
|
354 | writeData(file, tableOffsets[i], table);
|
355 | }
|
356 |
|
357 | if (sfnt === 'true') {
|
358 | sfnt = (0, _util.string32)(0x00010000);
|
359 | }
|
360 |
|
361 | file[0] = sfnt.charCodeAt(0) & 0xFF;
|
362 | file[1] = sfnt.charCodeAt(1) & 0xFF;
|
363 | file[2] = sfnt.charCodeAt(2) & 0xFF;
|
364 | file[3] = sfnt.charCodeAt(3) & 0xFF;
|
365 | writeInt16(file, 4, numTables);
|
366 | var searchParams = OpenTypeFileBuilder.getSearchParams(numTables, 16);
|
367 | writeInt16(file, 6, searchParams.range);
|
368 | writeInt16(file, 8, searchParams.entry);
|
369 | writeInt16(file, 10, searchParams.rangeShift);
|
370 | offset = OTF_HEADER_SIZE;
|
371 |
|
372 | for (i = 0; i < numTables; i++) {
|
373 | tableName = tablesNames[i];
|
374 | file[offset] = tableName.charCodeAt(0) & 0xFF;
|
375 | file[offset + 1] = tableName.charCodeAt(1) & 0xFF;
|
376 | file[offset + 2] = tableName.charCodeAt(2) & 0xFF;
|
377 | file[offset + 3] = tableName.charCodeAt(3) & 0xFF;
|
378 | var checksum = 0;
|
379 |
|
380 | for (j = tableOffsets[i], jj = tableOffsets[i + 1]; j < jj; j += 4) {
|
381 | var quad = (0, _util.readUint32)(file, j);
|
382 | checksum = checksum + quad >>> 0;
|
383 | }
|
384 |
|
385 | writeInt32(file, offset + 4, checksum);
|
386 | writeInt32(file, offset + 8, tableOffsets[i]);
|
387 | writeInt32(file, offset + 12, tables[tableName].length);
|
388 | offset += OTF_TABLE_ENTRY_SIZE;
|
389 | }
|
390 |
|
391 | return file;
|
392 | },
|
393 | addTable: function OpenTypeFileBuilder_addTable(tag, data) {
|
394 | if (tag in this.tables) {
|
395 | throw new Error('Table ' + tag + ' already exists');
|
396 | }
|
397 |
|
398 | this.tables[tag] = data;
|
399 | }
|
400 | };
|
401 | return OpenTypeFileBuilder;
|
402 | }();
|
403 |
|
404 | var Font = function FontClosure() {
|
405 | function Font(name, file, properties) {
|
406 | var charCode;
|
407 | this.name = name;
|
408 | this.loadedName = properties.loadedName;
|
409 | this.isType3Font = properties.isType3Font;
|
410 | this.sizes = [];
|
411 | this.missingFile = false;
|
412 | this.glyphCache = Object.create(null);
|
413 | this.isSerifFont = !!(properties.flags & FontFlags.Serif);
|
414 | this.isSymbolicFont = !!(properties.flags & FontFlags.Symbolic);
|
415 | this.isMonospace = !!(properties.flags & FontFlags.FixedPitch);
|
416 | var type = properties.type;
|
417 | var subtype = properties.subtype;
|
418 | this.type = type;
|
419 | this.subtype = subtype;
|
420 | this.fallbackName = this.isMonospace ? 'monospace' : this.isSerifFont ? 'serif' : 'sans-serif';
|
421 | this.differences = properties.differences;
|
422 | this.widths = properties.widths;
|
423 | this.defaultWidth = properties.defaultWidth;
|
424 | this.composite = properties.composite;
|
425 | this.wideChars = properties.wideChars;
|
426 | this.cMap = properties.cMap;
|
427 | this.ascent = properties.ascent / PDF_GLYPH_SPACE_UNITS;
|
428 | this.descent = properties.descent / PDF_GLYPH_SPACE_UNITS;
|
429 | this.fontMatrix = properties.fontMatrix;
|
430 | this.bbox = properties.bbox;
|
431 | this.defaultEncoding = properties.defaultEncoding;
|
432 | this.toUnicode = properties.toUnicode;
|
433 | this.fallbackToUnicode = properties.fallbackToUnicode || new ToUnicodeMap();
|
434 | this.toFontChar = [];
|
435 |
|
436 | if (properties.type === 'Type3') {
|
437 | for (charCode = 0; charCode < 256; charCode++) {
|
438 | this.toFontChar[charCode] = this.differences[charCode] || properties.defaultEncoding[charCode];
|
439 | }
|
440 |
|
441 | this.fontType = _util.FontType.TYPE3;
|
442 | return;
|
443 | }
|
444 |
|
445 | this.cidEncoding = properties.cidEncoding;
|
446 | this.vertical = properties.vertical;
|
447 |
|
448 | if (this.vertical) {
|
449 | this.vmetrics = properties.vmetrics;
|
450 | this.defaultVMetrics = properties.defaultVMetrics;
|
451 | }
|
452 |
|
453 | if (!file || file.isEmpty) {
|
454 | if (file) {
|
455 | (0, _util.warn)('Font file is empty in "' + name + '" (' + this.loadedName + ')');
|
456 | }
|
457 |
|
458 | this.fallbackToSystemFont();
|
459 | return;
|
460 | }
|
461 |
|
462 | var _getFontFileType = getFontFileType(file, properties);
|
463 |
|
464 | var _getFontFileType2 = _slicedToArray(_getFontFileType, 2);
|
465 |
|
466 | type = _getFontFileType2[0];
|
467 | subtype = _getFontFileType2[1];
|
468 |
|
469 | if (type !== this.type || subtype !== this.subtype) {
|
470 | (0, _util.info)('Inconsistent font file Type/SubType, expected: ' + "".concat(this.type, "/").concat(this.subtype, " but found: ").concat(type, "/").concat(subtype, "."));
|
471 | }
|
472 |
|
473 | try {
|
474 | var data;
|
475 |
|
476 | switch (type) {
|
477 | case 'MMType1':
|
478 | (0, _util.info)('MMType1 font (' + name + '), falling back to Type1.');
|
479 |
|
480 | case 'Type1':
|
481 | case 'CIDFontType0':
|
482 | this.mimetype = 'font/opentype';
|
483 | var cff = subtype === 'Type1C' || subtype === 'CIDFontType0C' ? new CFFFont(file, properties) : new Type1Font(name, file, properties);
|
484 | adjustWidths(properties);
|
485 | data = this.convert(name, cff, properties);
|
486 | break;
|
487 |
|
488 | case 'OpenType':
|
489 | case 'TrueType':
|
490 | case 'CIDFontType2':
|
491 | this.mimetype = 'font/opentype';
|
492 | data = this.checkAndRepair(name, file, properties);
|
493 |
|
494 | if (this.isOpenType) {
|
495 | adjustWidths(properties);
|
496 | type = 'OpenType';
|
497 | }
|
498 |
|
499 | break;
|
500 |
|
501 | default:
|
502 | throw new _util.FormatError("Font ".concat(type, " is not supported"));
|
503 | }
|
504 | } catch (e) {
|
505 | (0, _util.warn)(e);
|
506 | this.fallbackToSystemFont();
|
507 | return;
|
508 | }
|
509 |
|
510 | this.data = data;
|
511 | this.fontType = getFontType(type, subtype);
|
512 | this.fontMatrix = properties.fontMatrix;
|
513 | this.widths = properties.widths;
|
514 | this.defaultWidth = properties.defaultWidth;
|
515 | this.toUnicode = properties.toUnicode;
|
516 | this.encoding = properties.baseEncoding;
|
517 | this.seacMap = properties.seacMap;
|
518 | }
|
519 |
|
520 | Font.getFontID = function () {
|
521 | var ID = 1;
|
522 | return function Font_getFontID() {
|
523 | return String(ID++);
|
524 | };
|
525 | }();
|
526 |
|
527 | function int16(b0, b1) {
|
528 | return (b0 << 8) + b1;
|
529 | }
|
530 |
|
531 | function writeSignedInt16(bytes, index, value) {
|
532 | bytes[index + 1] = value;
|
533 | bytes[index] = value >>> 8;
|
534 | }
|
535 |
|
536 | function signedInt16(b0, b1) {
|
537 | var value = (b0 << 8) + b1;
|
538 | return value & 1 << 15 ? value - 0x10000 : value;
|
539 | }
|
540 |
|
541 | function int32(b0, b1, b2, b3) {
|
542 | return (b0 << 24) + (b1 << 16) + (b2 << 8) + b3;
|
543 | }
|
544 |
|
545 | function string16(value) {
|
546 | return String.fromCharCode(value >> 8 & 0xff, value & 0xff);
|
547 | }
|
548 |
|
549 | function safeString16(value) {
|
550 | value = value > 0x7FFF ? 0x7FFF : value < -0x8000 ? -0x8000 : value;
|
551 | return String.fromCharCode(value >> 8 & 0xff, value & 0xff);
|
552 | }
|
553 |
|
554 | function isTrueTypeFile(file) {
|
555 | var header = file.peekBytes(4);
|
556 | return (0, _util.readUint32)(header, 0) === 0x00010000 || (0, _util.bytesToString)(header) === 'true';
|
557 | }
|
558 |
|
559 | function isTrueTypeCollectionFile(file) {
|
560 | var header = file.peekBytes(4);
|
561 | return (0, _util.bytesToString)(header) === 'ttcf';
|
562 | }
|
563 |
|
564 | function isOpenTypeFile(file) {
|
565 | var header = file.peekBytes(4);
|
566 | return (0, _util.bytesToString)(header) === 'OTTO';
|
567 | }
|
568 |
|
569 | function isType1File(file) {
|
570 | var header = file.peekBytes(2);
|
571 |
|
572 | if (header[0] === 0x25 && header[1] === 0x21) {
|
573 | return true;
|
574 | }
|
575 |
|
576 | if (header[0] === 0x80 && header[1] === 0x01) {
|
577 | return true;
|
578 | }
|
579 |
|
580 | return false;
|
581 | }
|
582 |
|
583 | function isCFFFile(file) {
|
584 | var header = file.peekBytes(4);
|
585 |
|
586 | if (header[0] >= 1 && header[3] >= 1 && header[3] <= 4) {
|
587 | return true;
|
588 | }
|
589 |
|
590 | return false;
|
591 | }
|
592 |
|
593 | function getFontFileType(file, _ref) {
|
594 | var type = _ref.type,
|
595 | subtype = _ref.subtype,
|
596 | composite = _ref.composite;
|
597 | var fileType, fileSubtype;
|
598 |
|
599 | if (isTrueTypeFile(file) || isTrueTypeCollectionFile(file)) {
|
600 | if (composite) {
|
601 | fileType = 'CIDFontType2';
|
602 | } else {
|
603 | fileType = 'TrueType';
|
604 | }
|
605 | } else if (isOpenTypeFile(file)) {
|
606 | if (composite) {
|
607 | fileType = 'CIDFontType2';
|
608 | } else {
|
609 | fileType = 'OpenType';
|
610 | }
|
611 | } else if (isType1File(file)) {
|
612 | if (composite) {
|
613 | fileType = 'CIDFontType0';
|
614 | } else {
|
615 | fileType = type === 'MMType1' ? 'MMType1' : 'Type1';
|
616 | }
|
617 | } else if (isCFFFile(file)) {
|
618 | if (composite) {
|
619 | fileType = 'CIDFontType0';
|
620 | fileSubtype = 'CIDFontType0C';
|
621 | } else {
|
622 | fileType = type === 'MMType1' ? 'MMType1' : 'Type1';
|
623 | fileSubtype = 'Type1C';
|
624 | }
|
625 | } else {
|
626 | (0, _util.warn)('getFontFileType: Unable to detect correct font file Type/Subtype.');
|
627 | fileType = type;
|
628 | fileSubtype = subtype;
|
629 | }
|
630 |
|
631 | return [fileType, fileSubtype];
|
632 | }
|
633 |
|
634 | function buildToFontChar(encoding, glyphsUnicodeMap, differences) {
|
635 | var toFontChar = [],
|
636 | unicode;
|
637 |
|
638 | for (var i = 0, ii = encoding.length; i < ii; i++) {
|
639 | unicode = (0, _unicode.getUnicodeForGlyph)(encoding[i], glyphsUnicodeMap);
|
640 |
|
641 | if (unicode !== -1) {
|
642 | toFontChar[i] = unicode;
|
643 | }
|
644 | }
|
645 |
|
646 | for (var charCode in differences) {
|
647 | unicode = (0, _unicode.getUnicodeForGlyph)(differences[charCode], glyphsUnicodeMap);
|
648 |
|
649 | if (unicode !== -1) {
|
650 | toFontChar[+charCode] = unicode;
|
651 | }
|
652 | }
|
653 |
|
654 | return toFontChar;
|
655 | }
|
656 |
|
657 | function adjustMapping(charCodeToGlyphId, hasGlyph, newGlyphZeroId) {
|
658 | var newMap = Object.create(null);
|
659 | var toFontChar = [];
|
660 | var privateUseAreaIndex = 0;
|
661 | var nextAvailableFontCharCode = PRIVATE_USE_AREAS[privateUseAreaIndex][0];
|
662 | var privateUseOffetEnd = PRIVATE_USE_AREAS[privateUseAreaIndex][1];
|
663 |
|
664 | for (var originalCharCode in charCodeToGlyphId) {
|
665 | originalCharCode |= 0;
|
666 | var glyphId = charCodeToGlyphId[originalCharCode];
|
667 |
|
668 | if (!hasGlyph(glyphId)) {
|
669 | continue;
|
670 | }
|
671 |
|
672 | if (nextAvailableFontCharCode > privateUseOffetEnd) {
|
673 | privateUseAreaIndex++;
|
674 |
|
675 | if (privateUseAreaIndex >= PRIVATE_USE_AREAS.length) {
|
676 | (0, _util.warn)('Ran out of space in font private use area.');
|
677 | break;
|
678 | }
|
679 |
|
680 | nextAvailableFontCharCode = PRIVATE_USE_AREAS[privateUseAreaIndex][0];
|
681 | privateUseOffetEnd = PRIVATE_USE_AREAS[privateUseAreaIndex][1];
|
682 | }
|
683 |
|
684 | var fontCharCode = nextAvailableFontCharCode++;
|
685 |
|
686 | if (glyphId === 0) {
|
687 | glyphId = newGlyphZeroId;
|
688 | }
|
689 |
|
690 | newMap[fontCharCode] = glyphId;
|
691 | toFontChar[originalCharCode] = fontCharCode;
|
692 | }
|
693 |
|
694 | return {
|
695 | toFontChar: toFontChar,
|
696 | charCodeToGlyphId: newMap,
|
697 | nextAvailableFontCharCode: nextAvailableFontCharCode
|
698 | };
|
699 | }
|
700 |
|
701 | function getRanges(glyphs, numGlyphs) {
|
702 | var codes = [];
|
703 |
|
704 | for (var charCode in glyphs) {
|
705 | if (glyphs[charCode] >= numGlyphs) {
|
706 | continue;
|
707 | }
|
708 |
|
709 | codes.push({
|
710 | fontCharCode: charCode | 0,
|
711 | glyphId: glyphs[charCode]
|
712 | });
|
713 | }
|
714 |
|
715 | if (codes.length === 0) {
|
716 | codes.push({
|
717 | fontCharCode: 0,
|
718 | glyphId: 0
|
719 | });
|
720 | }
|
721 |
|
722 | codes.sort(function fontGetRangesSort(a, b) {
|
723 | return a.fontCharCode - b.fontCharCode;
|
724 | });
|
725 | var ranges = [];
|
726 | var length = codes.length;
|
727 |
|
728 | for (var n = 0; n < length;) {
|
729 | var start = codes[n].fontCharCode;
|
730 | var codeIndices = [codes[n].glyphId];
|
731 | ++n;
|
732 | var end = start;
|
733 |
|
734 | while (n < length && end + 1 === codes[n].fontCharCode) {
|
735 | codeIndices.push(codes[n].glyphId);
|
736 | ++end;
|
737 | ++n;
|
738 |
|
739 | if (end === 0xFFFF) {
|
740 | break;
|
741 | }
|
742 | }
|
743 |
|
744 | ranges.push([start, end, codeIndices]);
|
745 | }
|
746 |
|
747 | return ranges;
|
748 | }
|
749 |
|
750 | function createCmapTable(glyphs, numGlyphs) {
|
751 | var ranges = getRanges(glyphs, numGlyphs);
|
752 | var numTables = ranges[ranges.length - 1][1] > 0xFFFF ? 2 : 1;
|
753 | var cmap = '\x00\x00' + string16(numTables) + '\x00\x03' + '\x00\x01' + (0, _util.string32)(4 + numTables * 8);
|
754 | var i, ii, j, jj;
|
755 |
|
756 | for (i = ranges.length - 1; i >= 0; --i) {
|
757 | if (ranges[i][0] <= 0xFFFF) {
|
758 | break;
|
759 | }
|
760 | }
|
761 |
|
762 | var bmpLength = i + 1;
|
763 |
|
764 | if (ranges[i][0] < 0xFFFF && ranges[i][1] === 0xFFFF) {
|
765 | ranges[i][1] = 0xFFFE;
|
766 | }
|
767 |
|
768 | var trailingRangesCount = ranges[i][1] < 0xFFFF ? 1 : 0;
|
769 | var segCount = bmpLength + trailingRangesCount;
|
770 | var searchParams = OpenTypeFileBuilder.getSearchParams(segCount, 2);
|
771 | var startCount = '';
|
772 | var endCount = '';
|
773 | var idDeltas = '';
|
774 | var idRangeOffsets = '';
|
775 | var glyphsIds = '';
|
776 | var bias = 0;
|
777 | var range, start, end, codes;
|
778 |
|
779 | for (i = 0, ii = bmpLength; i < ii; i++) {
|
780 | range = ranges[i];
|
781 | start = range[0];
|
782 | end = range[1];
|
783 | startCount += string16(start);
|
784 | endCount += string16(end);
|
785 | codes = range[2];
|
786 | var contiguous = true;
|
787 |
|
788 | for (j = 1, jj = codes.length; j < jj; ++j) {
|
789 | if (codes[j] !== codes[j - 1] + 1) {
|
790 | contiguous = false;
|
791 | break;
|
792 | }
|
793 | }
|
794 |
|
795 | if (!contiguous) {
|
796 | var offset = (segCount - i) * 2 + bias * 2;
|
797 | bias += end - start + 1;
|
798 | idDeltas += string16(0);
|
799 | idRangeOffsets += string16(offset);
|
800 |
|
801 | for (j = 0, jj = codes.length; j < jj; ++j) {
|
802 | glyphsIds += string16(codes[j]);
|
803 | }
|
804 | } else {
|
805 | var startCode = codes[0];
|
806 | idDeltas += string16(startCode - start & 0xFFFF);
|
807 | idRangeOffsets += string16(0);
|
808 | }
|
809 | }
|
810 |
|
811 | if (trailingRangesCount > 0) {
|
812 | endCount += '\xFF\xFF';
|
813 | startCount += '\xFF\xFF';
|
814 | idDeltas += '\x00\x01';
|
815 | idRangeOffsets += '\x00\x00';
|
816 | }
|
817 |
|
818 | var format314 = '\x00\x00' + string16(2 * segCount) + string16(searchParams.range) + string16(searchParams.entry) + string16(searchParams.rangeShift) + endCount + '\x00\x00' + startCount + idDeltas + idRangeOffsets + glyphsIds;
|
819 | var format31012 = '';
|
820 | var header31012 = '';
|
821 |
|
822 | if (numTables > 1) {
|
823 | cmap += '\x00\x03' + '\x00\x0A' + (0, _util.string32)(4 + numTables * 8 + 4 + format314.length);
|
824 | format31012 = '';
|
825 |
|
826 | for (i = 0, ii = ranges.length; i < ii; i++) {
|
827 | range = ranges[i];
|
828 | start = range[0];
|
829 | codes = range[2];
|
830 | var code = codes[0];
|
831 |
|
832 | for (j = 1, jj = codes.length; j < jj; ++j) {
|
833 | if (codes[j] !== codes[j - 1] + 1) {
|
834 | end = range[0] + j - 1;
|
835 | format31012 += (0, _util.string32)(start) + (0, _util.string32)(end) + (0, _util.string32)(code);
|
836 | start = end + 1;
|
837 | code = codes[j];
|
838 | }
|
839 | }
|
840 |
|
841 | format31012 += (0, _util.string32)(start) + (0, _util.string32)(range[1]) + (0, _util.string32)(code);
|
842 | }
|
843 |
|
844 | header31012 = '\x00\x0C' + '\x00\x00' + (0, _util.string32)(format31012.length + 16) + '\x00\x00\x00\x00' + (0, _util.string32)(format31012.length / 12);
|
845 | }
|
846 |
|
847 | return cmap + '\x00\x04' + string16(format314.length + 4) + format314 + header31012 + format31012;
|
848 | }
|
849 |
|
850 | function validateOS2Table(os2) {
|
851 | var stream = new _stream.Stream(os2.data);
|
852 | var version = stream.getUint16();
|
853 | stream.getBytes(60);
|
854 | var selection = stream.getUint16();
|
855 |
|
856 | if (version < 4 && selection & 0x0300) {
|
857 | return false;
|
858 | }
|
859 |
|
860 | var firstChar = stream.getUint16();
|
861 | var lastChar = stream.getUint16();
|
862 |
|
863 | if (firstChar > lastChar) {
|
864 | return false;
|
865 | }
|
866 |
|
867 | stream.getBytes(6);
|
868 | var usWinAscent = stream.getUint16();
|
869 |
|
870 | if (usWinAscent === 0) {
|
871 | return false;
|
872 | }
|
873 |
|
874 | os2.data[8] = os2.data[9] = 0;
|
875 | return true;
|
876 | }
|
877 |
|
878 | function createOS2Table(properties, charstrings, override) {
|
879 | override = override || {
|
880 | unitsPerEm: 0,
|
881 | yMax: 0,
|
882 | yMin: 0,
|
883 | ascent: 0,
|
884 | descent: 0
|
885 | };
|
886 | var ulUnicodeRange1 = 0;
|
887 | var ulUnicodeRange2 = 0;
|
888 | var ulUnicodeRange3 = 0;
|
889 | var ulUnicodeRange4 = 0;
|
890 | var firstCharIndex = null;
|
891 | var lastCharIndex = 0;
|
892 |
|
893 | if (charstrings) {
|
894 | for (var code in charstrings) {
|
895 | code |= 0;
|
896 |
|
897 | if (firstCharIndex > code || !firstCharIndex) {
|
898 | firstCharIndex = code;
|
899 | }
|
900 |
|
901 | if (lastCharIndex < code) {
|
902 | lastCharIndex = code;
|
903 | }
|
904 |
|
905 | var position = (0, _unicode.getUnicodeRangeFor)(code);
|
906 |
|
907 | if (position < 32) {
|
908 | ulUnicodeRange1 |= 1 << position;
|
909 | } else if (position < 64) {
|
910 | ulUnicodeRange2 |= 1 << position - 32;
|
911 | } else if (position < 96) {
|
912 | ulUnicodeRange3 |= 1 << position - 64;
|
913 | } else if (position < 123) {
|
914 | ulUnicodeRange4 |= 1 << position - 96;
|
915 | } else {
|
916 | throw new _util.FormatError('Unicode ranges Bits > 123 are reserved for internal usage');
|
917 | }
|
918 | }
|
919 |
|
920 | if (lastCharIndex > 0xFFFF) {
|
921 | lastCharIndex = 0xFFFF;
|
922 | }
|
923 | } else {
|
924 | firstCharIndex = 0;
|
925 | lastCharIndex = 255;
|
926 | }
|
927 |
|
928 | var bbox = properties.bbox || [0, 0, 0, 0];
|
929 | var unitsPerEm = override.unitsPerEm || 1 / (properties.fontMatrix || _util.FONT_IDENTITY_MATRIX)[0];
|
930 | var scale = properties.ascentScaled ? 1.0 : unitsPerEm / PDF_GLYPH_SPACE_UNITS;
|
931 | var typoAscent = override.ascent || Math.round(scale * (properties.ascent || bbox[3]));
|
932 | var typoDescent = override.descent || Math.round(scale * (properties.descent || bbox[1]));
|
933 |
|
934 | if (typoDescent > 0 && properties.descent > 0 && bbox[1] < 0) {
|
935 | typoDescent = -typoDescent;
|
936 | }
|
937 |
|
938 | var winAscent = override.yMax || typoAscent;
|
939 | var winDescent = -override.yMin || -typoDescent;
|
940 | return '\x00\x03' + '\x02\x24' + '\x01\xF4' + '\x00\x05' + '\x00\x00' + '\x02\x8A' + '\x02\xBB' + '\x00\x00' + '\x00\x8C' + '\x02\x8A' + '\x02\xBB' + '\x00\x00' + '\x01\xDF' + '\x00\x31' + '\x01\x02' + '\x00\x00' + '\x00\x00\x06' + String.fromCharCode(properties.fixedPitch ? 0x09 : 0x00) + '\x00\x00\x00\x00\x00\x00' + (0, _util.string32)(ulUnicodeRange1) + (0, _util.string32)(ulUnicodeRange2) + (0, _util.string32)(ulUnicodeRange3) + (0, _util.string32)(ulUnicodeRange4) + '\x2A\x32\x31\x2A' + string16(properties.italicAngle ? 1 : 0) + string16(firstCharIndex || properties.firstChar) + string16(lastCharIndex || properties.lastChar) + string16(typoAscent) + string16(typoDescent) + '\x00\x64' + string16(winAscent) + string16(winDescent) + '\x00\x00\x00\x00' + '\x00\x00\x00\x00' + string16(properties.xHeight) + string16(properties.capHeight) + string16(0) + string16(firstCharIndex || properties.firstChar) + '\x00\x03';
|
941 | }
|
942 |
|
943 | function createPostTable(properties) {
|
944 | var angle = Math.floor(properties.italicAngle * Math.pow(2, 16));
|
945 | return '\x00\x03\x00\x00' + (0, _util.string32)(angle) + '\x00\x00' + '\x00\x00' + (0, _util.string32)(properties.fixedPitch) + '\x00\x00\x00\x00' + '\x00\x00\x00\x00' + '\x00\x00\x00\x00' + '\x00\x00\x00\x00';
|
946 | }
|
947 |
|
948 | function createNameTable(name, proto) {
|
949 | if (!proto) {
|
950 | proto = [[], []];
|
951 | }
|
952 |
|
953 | var strings = [proto[0][0] || 'Original licence', proto[0][1] || name, proto[0][2] || 'Unknown', proto[0][3] || 'uniqueID', proto[0][4] || name, proto[0][5] || 'Version 0.11', proto[0][6] || '', proto[0][7] || 'Unknown', proto[0][8] || 'Unknown', proto[0][9] || 'Unknown'];
|
954 | var stringsUnicode = [];
|
955 | var i, ii, j, jj, str;
|
956 |
|
957 | for (i = 0, ii = strings.length; i < ii; i++) {
|
958 | str = proto[1][i] || strings[i];
|
959 | var strBufUnicode = [];
|
960 |
|
961 | for (j = 0, jj = str.length; j < jj; j++) {
|
962 | strBufUnicode.push(string16(str.charCodeAt(j)));
|
963 | }
|
964 |
|
965 | stringsUnicode.push(strBufUnicode.join(''));
|
966 | }
|
967 |
|
968 | var names = [strings, stringsUnicode];
|
969 | var platforms = ['\x00\x01', '\x00\x03'];
|
970 | var encodings = ['\x00\x00', '\x00\x01'];
|
971 | var languages = ['\x00\x00', '\x04\x09'];
|
972 | var namesRecordCount = strings.length * platforms.length;
|
973 | var nameTable = '\x00\x00' + string16(namesRecordCount) + string16(namesRecordCount * 12 + 6);
|
974 | var strOffset = 0;
|
975 |
|
976 | for (i = 0, ii = platforms.length; i < ii; i++) {
|
977 | var strs = names[i];
|
978 |
|
979 | for (j = 0, jj = strs.length; j < jj; j++) {
|
980 | str = strs[j];
|
981 | var nameRecord = platforms[i] + encodings[i] + languages[i] + string16(j) + string16(str.length) + string16(strOffset);
|
982 | nameTable += nameRecord;
|
983 | strOffset += str.length;
|
984 | }
|
985 | }
|
986 |
|
987 | nameTable += strings.join('') + stringsUnicode.join('');
|
988 | return nameTable;
|
989 | }
|
990 |
|
991 | Font.prototype = {
|
992 | name: null,
|
993 | font: null,
|
994 | mimetype: null,
|
995 | encoding: null,
|
996 | disableFontFace: false,
|
997 |
|
998 | get renderer() {
|
999 | var renderer = _font_renderer.FontRendererFactory.create(this, SEAC_ANALYSIS_ENABLED);
|
1000 |
|
1001 | return (0, _util.shadow)(this, 'renderer', renderer);
|
1002 | },
|
1003 |
|
1004 | exportData: function Font_exportData() {
|
1005 | var data = {};
|
1006 |
|
1007 | for (var i in this) {
|
1008 | if (this.hasOwnProperty(i)) {
|
1009 | data[i] = this[i];
|
1010 | }
|
1011 | }
|
1012 |
|
1013 | return data;
|
1014 | },
|
1015 | fallbackToSystemFont: function Font_fallbackToSystemFont() {
|
1016 | var _this = this;
|
1017 |
|
1018 | this.missingFile = true;
|
1019 | var charCode, unicode;
|
1020 | var name = this.name;
|
1021 | var type = this.type;
|
1022 | var subtype = this.subtype;
|
1023 | var fontName = name.replace(/[,_]/g, '-');
|
1024 | var stdFontMap = (0, _standard_fonts.getStdFontMap)(),
|
1025 | nonStdFontMap = (0, _standard_fonts.getNonStdFontMap)();
|
1026 | var isStandardFont = !!stdFontMap[fontName] || !!(nonStdFontMap[fontName] && stdFontMap[nonStdFontMap[fontName]]);
|
1027 | fontName = stdFontMap[fontName] || nonStdFontMap[fontName] || fontName;
|
1028 | this.bold = fontName.search(/bold/gi) !== -1;
|
1029 | this.italic = fontName.search(/oblique/gi) !== -1 || fontName.search(/italic/gi) !== -1;
|
1030 | this.black = name.search(/Black/g) !== -1;
|
1031 | this.remeasure = Object.keys(this.widths).length > 0;
|
1032 |
|
1033 | if (isStandardFont && type === 'CIDFontType2' && this.cidEncoding.startsWith('Identity-')) {
|
1034 | var GlyphMapForStandardFonts = (0, _standard_fonts.getGlyphMapForStandardFonts)();
|
1035 | var map = [];
|
1036 |
|
1037 | for (charCode in GlyphMapForStandardFonts) {
|
1038 | map[+charCode] = GlyphMapForStandardFonts[charCode];
|
1039 | }
|
1040 |
|
1041 | if (/Arial-?Black/i.test(name)) {
|
1042 | var SupplementalGlyphMapForArialBlack = (0, _standard_fonts.getSupplementalGlyphMapForArialBlack)();
|
1043 |
|
1044 | for (charCode in SupplementalGlyphMapForArialBlack) {
|
1045 | map[+charCode] = SupplementalGlyphMapForArialBlack[charCode];
|
1046 | }
|
1047 | } else if (/Calibri/i.test(name)) {
|
1048 | var SupplementalGlyphMapForCalibri = (0, _standard_fonts.getSupplementalGlyphMapForCalibri)();
|
1049 |
|
1050 | for (charCode in SupplementalGlyphMapForCalibri) {
|
1051 | map[+charCode] = SupplementalGlyphMapForCalibri[charCode];
|
1052 | }
|
1053 | }
|
1054 |
|
1055 | var isIdentityUnicode = this.toUnicode instanceof IdentityToUnicodeMap;
|
1056 |
|
1057 | if (!isIdentityUnicode) {
|
1058 | this.toUnicode.forEach(function (charCode, unicodeCharCode) {
|
1059 | map[+charCode] = unicodeCharCode;
|
1060 | });
|
1061 | }
|
1062 |
|
1063 | this.toFontChar = map;
|
1064 | this.toUnicode = new ToUnicodeMap(map);
|
1065 | } else if (/Symbol/i.test(fontName)) {
|
1066 | this.toFontChar = buildToFontChar(_encodings.SymbolSetEncoding, (0, _glyphlist.getGlyphsUnicode)(), this.differences);
|
1067 | } else if (/Dingbats/i.test(fontName)) {
|
1068 | if (/Wingdings/i.test(name)) {
|
1069 | (0, _util.warn)('Non-embedded Wingdings font, falling back to ZapfDingbats.');
|
1070 | }
|
1071 |
|
1072 | this.toFontChar = buildToFontChar(_encodings.ZapfDingbatsEncoding, (0, _glyphlist.getDingbatsGlyphsUnicode)(), this.differences);
|
1073 | } else if (isStandardFont) {
|
1074 | this.toFontChar = buildToFontChar(this.defaultEncoding, (0, _glyphlist.getGlyphsUnicode)(), this.differences);
|
1075 | } else {
|
1076 | var glyphsUnicodeMap = (0, _glyphlist.getGlyphsUnicode)();
|
1077 | this.toUnicode.forEach(function (charCode, unicodeCharCode) {
|
1078 | if (!_this.composite) {
|
1079 | var glyphName = _this.differences[charCode] || _this.defaultEncoding[charCode];
|
1080 | unicode = (0, _unicode.getUnicodeForGlyph)(glyphName, glyphsUnicodeMap);
|
1081 |
|
1082 | if (unicode !== -1) {
|
1083 | unicodeCharCode = unicode;
|
1084 | }
|
1085 | }
|
1086 |
|
1087 | _this.toFontChar[charCode] = unicodeCharCode;
|
1088 | });
|
1089 | }
|
1090 |
|
1091 | this.loadedName = fontName.split('-')[0];
|
1092 | this.fontType = getFontType(type, subtype);
|
1093 | },
|
1094 | checkAndRepair: function Font_checkAndRepair(name, font, properties) {
|
1095 | var VALID_TABLES = ['OS/2', 'cmap', 'head', 'hhea', 'hmtx', 'maxp', 'name', 'post', 'loca', 'glyf', 'fpgm', 'prep', 'cvt ', 'CFF '];
|
1096 |
|
1097 | function readTables(file, numTables) {
|
1098 | var tables = Object.create(null);
|
1099 | tables['OS/2'] = null;
|
1100 | tables['cmap'] = null;
|
1101 | tables['head'] = null;
|
1102 | tables['hhea'] = null;
|
1103 | tables['hmtx'] = null;
|
1104 | tables['maxp'] = null;
|
1105 | tables['name'] = null;
|
1106 | tables['post'] = null;
|
1107 |
|
1108 | for (var i = 0; i < numTables; i++) {
|
1109 | var table = readTableEntry(font);
|
1110 |
|
1111 | if (!VALID_TABLES.includes(table.tag)) {
|
1112 | continue;
|
1113 | }
|
1114 |
|
1115 | if (table.length === 0) {
|
1116 | continue;
|
1117 | }
|
1118 |
|
1119 | tables[table.tag] = table;
|
1120 | }
|
1121 |
|
1122 | return tables;
|
1123 | }
|
1124 |
|
1125 | function readTableEntry(file) {
|
1126 | var tag = (0, _util.bytesToString)(file.getBytes(4));
|
1127 | var checksum = file.getInt32() >>> 0;
|
1128 | var offset = file.getInt32() >>> 0;
|
1129 | var length = file.getInt32() >>> 0;
|
1130 | var previousPosition = file.pos;
|
1131 | file.pos = file.start ? file.start : 0;
|
1132 | file.skip(offset);
|
1133 | var data = file.getBytes(length);
|
1134 | file.pos = previousPosition;
|
1135 |
|
1136 | if (tag === 'head') {
|
1137 | data[8] = data[9] = data[10] = data[11] = 0;
|
1138 | data[17] |= 0x20;
|
1139 | }
|
1140 |
|
1141 | return {
|
1142 | tag: tag,
|
1143 | checksum: checksum,
|
1144 | length: length,
|
1145 | offset: offset,
|
1146 | data: data
|
1147 | };
|
1148 | }
|
1149 |
|
1150 | function readOpenTypeHeader(ttf) {
|
1151 | return {
|
1152 | version: (0, _util.bytesToString)(ttf.getBytes(4)),
|
1153 | numTables: ttf.getUint16(),
|
1154 | searchRange: ttf.getUint16(),
|
1155 | entrySelector: ttf.getUint16(),
|
1156 | rangeShift: ttf.getUint16()
|
1157 | };
|
1158 | }
|
1159 |
|
1160 | function readTrueTypeCollectionHeader(ttc) {
|
1161 | var ttcTag = (0, _util.bytesToString)(ttc.getBytes(4));
|
1162 | (0, _util.assert)(ttcTag === 'ttcf', 'Must be a TrueType Collection font.');
|
1163 | var majorVersion = ttc.getUint16();
|
1164 | var minorVersion = ttc.getUint16();
|
1165 | var numFonts = ttc.getInt32() >>> 0;
|
1166 | var offsetTable = [];
|
1167 |
|
1168 | for (var i = 0; i < numFonts; i++) {
|
1169 | offsetTable.push(ttc.getInt32() >>> 0);
|
1170 | }
|
1171 |
|
1172 | var header = {
|
1173 | ttcTag: ttcTag,
|
1174 | majorVersion: majorVersion,
|
1175 | minorVersion: minorVersion,
|
1176 | numFonts: numFonts,
|
1177 | offsetTable: offsetTable
|
1178 | };
|
1179 |
|
1180 | switch (majorVersion) {
|
1181 | case 1:
|
1182 | return header;
|
1183 |
|
1184 | case 2:
|
1185 | header.dsigTag = ttc.getInt32() >>> 0;
|
1186 | header.dsigLength = ttc.getInt32() >>> 0;
|
1187 | header.dsigOffset = ttc.getInt32() >>> 0;
|
1188 | return header;
|
1189 | }
|
1190 |
|
1191 | throw new _util.FormatError("Invalid TrueType Collection majorVersion: ".concat(majorVersion, "."));
|
1192 | }
|
1193 |
|
1194 | function readTrueTypeCollectionData(ttc, fontName) {
|
1195 | var _readTrueTypeCollecti = readTrueTypeCollectionHeader(ttc),
|
1196 | numFonts = _readTrueTypeCollecti.numFonts,
|
1197 | offsetTable = _readTrueTypeCollecti.offsetTable;
|
1198 |
|
1199 | for (var i = 0; i < numFonts; i++) {
|
1200 | ttc.pos = (ttc.start || 0) + offsetTable[i];
|
1201 | var potentialHeader = readOpenTypeHeader(ttc);
|
1202 | var potentialTables = readTables(ttc, potentialHeader.numTables);
|
1203 |
|
1204 | if (!potentialTables['name']) {
|
1205 | throw new _util.FormatError('TrueType Collection font must contain a "name" table.');
|
1206 | }
|
1207 |
|
1208 | var nameTable = readNameTable(potentialTables['name']);
|
1209 |
|
1210 | for (var j = 0, jj = nameTable.length; j < jj; j++) {
|
1211 | for (var k = 0, kk = nameTable[j].length; k < kk; k++) {
|
1212 | var nameEntry = nameTable[j][k];
|
1213 |
|
1214 | if (nameEntry && nameEntry.replace(/\s/g, '') === fontName) {
|
1215 | return {
|
1216 | header: potentialHeader,
|
1217 | tables: potentialTables
|
1218 | };
|
1219 | }
|
1220 | }
|
1221 | }
|
1222 | }
|
1223 |
|
1224 | throw new _util.FormatError("TrueType Collection does not contain \"".concat(fontName, "\" font."));
|
1225 | }
|
1226 |
|
1227 | function readCmapTable(cmap, font, isSymbolicFont, hasEncoding) {
|
1228 | if (!cmap) {
|
1229 | (0, _util.warn)('No cmap table available.');
|
1230 | return {
|
1231 | platformId: -1,
|
1232 | encodingId: -1,
|
1233 | mappings: [],
|
1234 | hasShortCmap: false
|
1235 | };
|
1236 | }
|
1237 |
|
1238 | var segment;
|
1239 | var start = (font.start ? font.start : 0) + cmap.offset;
|
1240 | font.pos = start;
|
1241 | font.getUint16();
|
1242 | var numTables = font.getUint16();
|
1243 | var potentialTable;
|
1244 | var canBreak = false;
|
1245 |
|
1246 | for (var i = 0; i < numTables; i++) {
|
1247 | var platformId = font.getUint16();
|
1248 | var encodingId = font.getUint16();
|
1249 | var offset = font.getInt32() >>> 0;
|
1250 | var useTable = false;
|
1251 |
|
1252 | if (potentialTable && potentialTable.platformId === platformId && potentialTable.encodingId === encodingId) {
|
1253 | continue;
|
1254 | }
|
1255 |
|
1256 | if (platformId === 0 && encodingId === 0) {
|
1257 | useTable = true;
|
1258 | } else if (platformId === 1 && encodingId === 0) {
|
1259 | useTable = true;
|
1260 | } else if (platformId === 3 && encodingId === 1 && (hasEncoding || !potentialTable)) {
|
1261 | useTable = true;
|
1262 |
|
1263 | if (!isSymbolicFont) {
|
1264 | canBreak = true;
|
1265 | }
|
1266 | } else if (isSymbolicFont && platformId === 3 && encodingId === 0) {
|
1267 | useTable = true;
|
1268 | canBreak = true;
|
1269 | }
|
1270 |
|
1271 | if (useTable) {
|
1272 | potentialTable = {
|
1273 | platformId: platformId,
|
1274 | encodingId: encodingId,
|
1275 | offset: offset
|
1276 | };
|
1277 | }
|
1278 |
|
1279 | if (canBreak) {
|
1280 | break;
|
1281 | }
|
1282 | }
|
1283 |
|
1284 | if (potentialTable) {
|
1285 | font.pos = start + potentialTable.offset;
|
1286 | }
|
1287 |
|
1288 | if (!potentialTable || font.peekByte() === -1) {
|
1289 | (0, _util.warn)('Could not find a preferred cmap table.');
|
1290 | return {
|
1291 | platformId: -1,
|
1292 | encodingId: -1,
|
1293 | mappings: [],
|
1294 | hasShortCmap: false
|
1295 | };
|
1296 | }
|
1297 |
|
1298 | var format = font.getUint16();
|
1299 | font.getUint16();
|
1300 | font.getUint16();
|
1301 | var hasShortCmap = false;
|
1302 | var mappings = [];
|
1303 | var j, glyphId;
|
1304 |
|
1305 | if (format === 0) {
|
1306 | for (j = 0; j < 256; j++) {
|
1307 | var index = font.getByte();
|
1308 |
|
1309 | if (!index) {
|
1310 | continue;
|
1311 | }
|
1312 |
|
1313 | mappings.push({
|
1314 | charCode: j,
|
1315 | glyphId: index
|
1316 | });
|
1317 | }
|
1318 |
|
1319 | hasShortCmap = true;
|
1320 | } else if (format === 4) {
|
1321 | var segCount = font.getUint16() >> 1;
|
1322 | font.getBytes(6);
|
1323 | var segIndex,
|
1324 | segments = [];
|
1325 |
|
1326 | for (segIndex = 0; segIndex < segCount; segIndex++) {
|
1327 | segments.push({
|
1328 | end: font.getUint16()
|
1329 | });
|
1330 | }
|
1331 |
|
1332 | font.getUint16();
|
1333 |
|
1334 | for (segIndex = 0; segIndex < segCount; segIndex++) {
|
1335 | segments[segIndex].start = font.getUint16();
|
1336 | }
|
1337 |
|
1338 | for (segIndex = 0; segIndex < segCount; segIndex++) {
|
1339 | segments[segIndex].delta = font.getUint16();
|
1340 | }
|
1341 |
|
1342 | var offsetsCount = 0;
|
1343 |
|
1344 | for (segIndex = 0; segIndex < segCount; segIndex++) {
|
1345 | segment = segments[segIndex];
|
1346 | var rangeOffset = font.getUint16();
|
1347 |
|
1348 | if (!rangeOffset) {
|
1349 | segment.offsetIndex = -1;
|
1350 | continue;
|
1351 | }
|
1352 |
|
1353 | var offsetIndex = (rangeOffset >> 1) - (segCount - segIndex);
|
1354 | segment.offsetIndex = offsetIndex;
|
1355 | offsetsCount = Math.max(offsetsCount, offsetIndex + segment.end - segment.start + 1);
|
1356 | }
|
1357 |
|
1358 | var offsets = [];
|
1359 |
|
1360 | for (j = 0; j < offsetsCount; j++) {
|
1361 | offsets.push(font.getUint16());
|
1362 | }
|
1363 |
|
1364 | for (segIndex = 0; segIndex < segCount; segIndex++) {
|
1365 | segment = segments[segIndex];
|
1366 | start = segment.start;
|
1367 | var end = segment.end;
|
1368 | var delta = segment.delta;
|
1369 | offsetIndex = segment.offsetIndex;
|
1370 |
|
1371 | for (j = start; j <= end; j++) {
|
1372 | if (j === 0xFFFF) {
|
1373 | continue;
|
1374 | }
|
1375 |
|
1376 | glyphId = offsetIndex < 0 ? j : offsets[offsetIndex + j - start];
|
1377 | glyphId = glyphId + delta & 0xFFFF;
|
1378 | mappings.push({
|
1379 | charCode: j,
|
1380 | glyphId: glyphId
|
1381 | });
|
1382 | }
|
1383 | }
|
1384 | } else if (format === 6) {
|
1385 | var firstCode = font.getUint16();
|
1386 | var entryCount = font.getUint16();
|
1387 |
|
1388 | for (j = 0; j < entryCount; j++) {
|
1389 | glyphId = font.getUint16();
|
1390 | var charCode = firstCode + j;
|
1391 | mappings.push({
|
1392 | charCode: charCode,
|
1393 | glyphId: glyphId
|
1394 | });
|
1395 | }
|
1396 | } else {
|
1397 | (0, _util.warn)('cmap table has unsupported format: ' + format);
|
1398 | return {
|
1399 | platformId: -1,
|
1400 | encodingId: -1,
|
1401 | mappings: [],
|
1402 | hasShortCmap: false
|
1403 | };
|
1404 | }
|
1405 |
|
1406 | mappings.sort(function (a, b) {
|
1407 | return a.charCode - b.charCode;
|
1408 | });
|
1409 |
|
1410 | for (i = 1; i < mappings.length; i++) {
|
1411 | if (mappings[i - 1].charCode === mappings[i].charCode) {
|
1412 | mappings.splice(i, 1);
|
1413 | i--;
|
1414 | }
|
1415 | }
|
1416 |
|
1417 | return {
|
1418 | platformId: potentialTable.platformId,
|
1419 | encodingId: potentialTable.encodingId,
|
1420 | mappings: mappings,
|
1421 | hasShortCmap: hasShortCmap
|
1422 | };
|
1423 | }
|
1424 |
|
1425 | function sanitizeMetrics(font, header, metrics, numGlyphs) {
|
1426 | if (!header) {
|
1427 | if (metrics) {
|
1428 | metrics.data = null;
|
1429 | }
|
1430 |
|
1431 | return;
|
1432 | }
|
1433 |
|
1434 | font.pos = (font.start ? font.start : 0) + header.offset;
|
1435 | font.pos += 4;
|
1436 | font.pos += 2;
|
1437 | font.pos += 2;
|
1438 | font.pos += 2;
|
1439 | font.pos += 2;
|
1440 | font.pos += 2;
|
1441 | font.pos += 2;
|
1442 | font.pos += 2;
|
1443 | font.pos += 2;
|
1444 | font.pos += 2;
|
1445 | font.pos += 2;
|
1446 | font.pos += 8;
|
1447 | font.pos += 2;
|
1448 | var numOfMetrics = font.getUint16();
|
1449 |
|
1450 | if (numOfMetrics > numGlyphs) {
|
1451 | (0, _util.info)('The numOfMetrics (' + numOfMetrics + ') should not be ' + 'greater than the numGlyphs (' + numGlyphs + ')');
|
1452 | numOfMetrics = numGlyphs;
|
1453 | header.data[34] = (numOfMetrics & 0xff00) >> 8;
|
1454 | header.data[35] = numOfMetrics & 0x00ff;
|
1455 | }
|
1456 |
|
1457 | var numOfSidebearings = numGlyphs - numOfMetrics;
|
1458 | var numMissing = numOfSidebearings - (metrics.length - numOfMetrics * 4 >> 1);
|
1459 |
|
1460 | if (numMissing > 0) {
|
1461 | var entries = new Uint8Array(metrics.length + numMissing * 2);
|
1462 | entries.set(metrics.data);
|
1463 | metrics.data = entries;
|
1464 | }
|
1465 | }
|
1466 |
|
1467 | function sanitizeGlyph(source, sourceStart, sourceEnd, dest, destStart, hintsValid) {
|
1468 | var glyphProfile = {
|
1469 | length: 0,
|
1470 | sizeOfInstructions: 0
|
1471 | };
|
1472 |
|
1473 | if (sourceEnd - sourceStart <= 12) {
|
1474 | return glyphProfile;
|
1475 | }
|
1476 |
|
1477 | var glyf = source.subarray(sourceStart, sourceEnd);
|
1478 | var contoursCount = signedInt16(glyf[0], glyf[1]);
|
1479 |
|
1480 | if (contoursCount < 0) {
|
1481 | contoursCount = -1;
|
1482 | writeSignedInt16(glyf, 0, contoursCount);
|
1483 | dest.set(glyf, destStart);
|
1484 | glyphProfile.length = glyf.length;
|
1485 | return glyphProfile;
|
1486 | }
|
1487 |
|
1488 | var i,
|
1489 | j = 10,
|
1490 | flagsCount = 0;
|
1491 |
|
1492 | for (i = 0; i < contoursCount; i++) {
|
1493 | var endPoint = glyf[j] << 8 | glyf[j + 1];
|
1494 | flagsCount = endPoint + 1;
|
1495 | j += 2;
|
1496 | }
|
1497 |
|
1498 | var instructionsStart = j;
|
1499 | var instructionsLength = glyf[j] << 8 | glyf[j + 1];
|
1500 | glyphProfile.sizeOfInstructions = instructionsLength;
|
1501 | j += 2 + instructionsLength;
|
1502 | var instructionsEnd = j;
|
1503 | var coordinatesLength = 0;
|
1504 |
|
1505 | for (i = 0; i < flagsCount; i++) {
|
1506 | var flag = glyf[j++];
|
1507 |
|
1508 | if (flag & 0xC0) {
|
1509 | glyf[j - 1] = flag & 0x3F;
|
1510 | }
|
1511 |
|
1512 | var xyLength = (flag & 2 ? 1 : flag & 16 ? 0 : 2) + (flag & 4 ? 1 : flag & 32 ? 0 : 2);
|
1513 | coordinatesLength += xyLength;
|
1514 |
|
1515 | if (flag & 8) {
|
1516 | var repeat = glyf[j++];
|
1517 | i += repeat;
|
1518 | coordinatesLength += repeat * xyLength;
|
1519 | }
|
1520 | }
|
1521 |
|
1522 | if (coordinatesLength === 0) {
|
1523 | return glyphProfile;
|
1524 | }
|
1525 |
|
1526 | var glyphDataLength = j + coordinatesLength;
|
1527 |
|
1528 | if (glyphDataLength > glyf.length) {
|
1529 | return glyphProfile;
|
1530 | }
|
1531 |
|
1532 | if (!hintsValid && instructionsLength > 0) {
|
1533 | dest.set(glyf.subarray(0, instructionsStart), destStart);
|
1534 | dest.set([0, 0], destStart + instructionsStart);
|
1535 | dest.set(glyf.subarray(instructionsEnd, glyphDataLength), destStart + instructionsStart + 2);
|
1536 | glyphDataLength -= instructionsLength;
|
1537 |
|
1538 | if (glyf.length - glyphDataLength > 3) {
|
1539 | glyphDataLength = glyphDataLength + 3 & ~3;
|
1540 | }
|
1541 |
|
1542 | glyphProfile.length = glyphDataLength;
|
1543 | return glyphProfile;
|
1544 | }
|
1545 |
|
1546 | if (glyf.length - glyphDataLength > 3) {
|
1547 | glyphDataLength = glyphDataLength + 3 & ~3;
|
1548 | dest.set(glyf.subarray(0, glyphDataLength), destStart);
|
1549 | glyphProfile.length = glyphDataLength;
|
1550 | return glyphProfile;
|
1551 | }
|
1552 |
|
1553 | dest.set(glyf, destStart);
|
1554 | glyphProfile.length = glyf.length;
|
1555 | return glyphProfile;
|
1556 | }
|
1557 |
|
1558 | function sanitizeHead(head, numGlyphs, locaLength) {
|
1559 | var data = head.data;
|
1560 | var version = int32(data[0], data[1], data[2], data[3]);
|
1561 |
|
1562 | if (version >> 16 !== 1) {
|
1563 | (0, _util.info)('Attempting to fix invalid version in head table: ' + version);
|
1564 | data[0] = 0;
|
1565 | data[1] = 1;
|
1566 | data[2] = 0;
|
1567 | data[3] = 0;
|
1568 | }
|
1569 |
|
1570 | var indexToLocFormat = int16(data[50], data[51]);
|
1571 |
|
1572 | if (indexToLocFormat < 0 || indexToLocFormat > 1) {
|
1573 | (0, _util.info)('Attempting to fix invalid indexToLocFormat in head table: ' + indexToLocFormat);
|
1574 | var numGlyphsPlusOne = numGlyphs + 1;
|
1575 |
|
1576 | if (locaLength === numGlyphsPlusOne << 1) {
|
1577 | data[50] = 0;
|
1578 | data[51] = 0;
|
1579 | } else if (locaLength === numGlyphsPlusOne << 2) {
|
1580 | data[50] = 0;
|
1581 | data[51] = 1;
|
1582 | } else {
|
1583 | throw new _util.FormatError('Could not fix indexToLocFormat: ' + indexToLocFormat);
|
1584 | }
|
1585 | }
|
1586 | }
|
1587 |
|
1588 | function sanitizeGlyphLocations(loca, glyf, numGlyphs, isGlyphLocationsLong, hintsValid, dupFirstEntry, maxSizeOfInstructions) {
|
1589 | var itemSize, itemDecode, itemEncode;
|
1590 |
|
1591 | if (isGlyphLocationsLong) {
|
1592 | itemSize = 4;
|
1593 |
|
1594 | itemDecode = function fontItemDecodeLong(data, offset) {
|
1595 | return data[offset] << 24 | data[offset + 1] << 16 | data[offset + 2] << 8 | data[offset + 3];
|
1596 | };
|
1597 |
|
1598 | itemEncode = function fontItemEncodeLong(data, offset, value) {
|
1599 | data[offset] = value >>> 24 & 0xFF;
|
1600 | data[offset + 1] = value >> 16 & 0xFF;
|
1601 | data[offset + 2] = value >> 8 & 0xFF;
|
1602 | data[offset + 3] = value & 0xFF;
|
1603 | };
|
1604 | } else {
|
1605 | itemSize = 2;
|
1606 |
|
1607 | itemDecode = function fontItemDecode(data, offset) {
|
1608 | return data[offset] << 9 | data[offset + 1] << 1;
|
1609 | };
|
1610 |
|
1611 | itemEncode = function fontItemEncode(data, offset, value) {
|
1612 | data[offset] = value >> 9 & 0xFF;
|
1613 | data[offset + 1] = value >> 1 & 0xFF;
|
1614 | };
|
1615 | }
|
1616 |
|
1617 | var numGlyphsOut = dupFirstEntry ? numGlyphs + 1 : numGlyphs;
|
1618 | var locaData = loca.data;
|
1619 | var locaDataSize = itemSize * (1 + numGlyphsOut);
|
1620 | locaData = new Uint8Array(locaDataSize);
|
1621 | locaData.set(loca.data.subarray(0, locaDataSize));
|
1622 | loca.data = locaData;
|
1623 | var oldGlyfData = glyf.data;
|
1624 | var oldGlyfDataLength = oldGlyfData.length;
|
1625 | var newGlyfData = new Uint8Array(oldGlyfDataLength);
|
1626 | var startOffset = itemDecode(locaData, 0);
|
1627 | var writeOffset = 0;
|
1628 | var missingGlyphs = Object.create(null);
|
1629 | itemEncode(locaData, 0, writeOffset);
|
1630 | var i, j;
|
1631 |
|
1632 | for (i = 0, j = itemSize; i < numGlyphs; i++, j += itemSize) {
|
1633 | var endOffset = itemDecode(locaData, j);
|
1634 |
|
1635 | if (endOffset === 0) {
|
1636 | endOffset = startOffset;
|
1637 | }
|
1638 |
|
1639 | if (endOffset > oldGlyfDataLength && (oldGlyfDataLength + 3 & ~3) === endOffset) {
|
1640 | endOffset = oldGlyfDataLength;
|
1641 | }
|
1642 |
|
1643 | if (endOffset > oldGlyfDataLength) {
|
1644 | startOffset = endOffset;
|
1645 | }
|
1646 |
|
1647 | var glyphProfile = sanitizeGlyph(oldGlyfData, startOffset, endOffset, newGlyfData, writeOffset, hintsValid);
|
1648 | var newLength = glyphProfile.length;
|
1649 |
|
1650 | if (newLength === 0) {
|
1651 | missingGlyphs[i] = true;
|
1652 | }
|
1653 |
|
1654 | if (glyphProfile.sizeOfInstructions > maxSizeOfInstructions) {
|
1655 | maxSizeOfInstructions = glyphProfile.sizeOfInstructions;
|
1656 | }
|
1657 |
|
1658 | writeOffset += newLength;
|
1659 | itemEncode(locaData, j, writeOffset);
|
1660 | startOffset = endOffset;
|
1661 | }
|
1662 |
|
1663 | if (writeOffset === 0) {
|
1664 | var simpleGlyph = new Uint8Array([0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49, 0]);
|
1665 |
|
1666 | for (i = 0, j = itemSize; i < numGlyphsOut; i++, j += itemSize) {
|
1667 | itemEncode(locaData, j, simpleGlyph.length);
|
1668 | }
|
1669 |
|
1670 | glyf.data = simpleGlyph;
|
1671 | } else if (dupFirstEntry) {
|
1672 | var firstEntryLength = itemDecode(locaData, itemSize);
|
1673 |
|
1674 | if (newGlyfData.length > firstEntryLength + writeOffset) {
|
1675 | glyf.data = newGlyfData.subarray(0, firstEntryLength + writeOffset);
|
1676 | } else {
|
1677 | glyf.data = new Uint8Array(firstEntryLength + writeOffset);
|
1678 | glyf.data.set(newGlyfData.subarray(0, writeOffset));
|
1679 | }
|
1680 |
|
1681 | glyf.data.set(newGlyfData.subarray(0, firstEntryLength), writeOffset);
|
1682 | itemEncode(loca.data, locaData.length - itemSize, writeOffset + firstEntryLength);
|
1683 | } else {
|
1684 | glyf.data = newGlyfData.subarray(0, writeOffset);
|
1685 | }
|
1686 |
|
1687 | return {
|
1688 | missingGlyphs: missingGlyphs,
|
1689 | maxSizeOfInstructions: maxSizeOfInstructions
|
1690 | };
|
1691 | }
|
1692 |
|
1693 | function readPostScriptTable(post, properties, maxpNumGlyphs) {
|
1694 | var start = (font.start ? font.start : 0) + post.offset;
|
1695 | font.pos = start;
|
1696 | var length = post.length,
|
1697 | end = start + length;
|
1698 | var version = font.getInt32();
|
1699 | font.getBytes(28);
|
1700 | var glyphNames;
|
1701 | var valid = true;
|
1702 | var i;
|
1703 |
|
1704 | switch (version) {
|
1705 | case 0x00010000:
|
1706 | glyphNames = MacStandardGlyphOrdering;
|
1707 | break;
|
1708 |
|
1709 | case 0x00020000:
|
1710 | var numGlyphs = font.getUint16();
|
1711 |
|
1712 | if (numGlyphs !== maxpNumGlyphs) {
|
1713 | valid = false;
|
1714 | break;
|
1715 | }
|
1716 |
|
1717 | var glyphNameIndexes = [];
|
1718 |
|
1719 | for (i = 0; i < numGlyphs; ++i) {
|
1720 | var index = font.getUint16();
|
1721 |
|
1722 | if (index >= 32768) {
|
1723 | valid = false;
|
1724 | break;
|
1725 | }
|
1726 |
|
1727 | glyphNameIndexes.push(index);
|
1728 | }
|
1729 |
|
1730 | if (!valid) {
|
1731 | break;
|
1732 | }
|
1733 |
|
1734 | var customNames = [];
|
1735 | var strBuf = [];
|
1736 |
|
1737 | while (font.pos < end) {
|
1738 | var stringLength = font.getByte();
|
1739 | strBuf.length = stringLength;
|
1740 |
|
1741 | for (i = 0; i < stringLength; ++i) {
|
1742 | strBuf[i] = String.fromCharCode(font.getByte());
|
1743 | }
|
1744 |
|
1745 | customNames.push(strBuf.join(''));
|
1746 | }
|
1747 |
|
1748 | glyphNames = [];
|
1749 |
|
1750 | for (i = 0; i < numGlyphs; ++i) {
|
1751 | var j = glyphNameIndexes[i];
|
1752 |
|
1753 | if (j < 258) {
|
1754 | glyphNames.push(MacStandardGlyphOrdering[j]);
|
1755 | continue;
|
1756 | }
|
1757 |
|
1758 | glyphNames.push(customNames[j - 258]);
|
1759 | }
|
1760 |
|
1761 | break;
|
1762 |
|
1763 | case 0x00030000:
|
1764 | break;
|
1765 |
|
1766 | default:
|
1767 | (0, _util.warn)('Unknown/unsupported post table version ' + version);
|
1768 | valid = false;
|
1769 |
|
1770 | if (properties.defaultEncoding) {
|
1771 | glyphNames = properties.defaultEncoding;
|
1772 | }
|
1773 |
|
1774 | break;
|
1775 | }
|
1776 |
|
1777 | properties.glyphNames = glyphNames;
|
1778 | return valid;
|
1779 | }
|
1780 |
|
1781 | function readNameTable(nameTable) {
|
1782 | var start = (font.start ? font.start : 0) + nameTable.offset;
|
1783 | font.pos = start;
|
1784 | var names = [[], []];
|
1785 | var length = nameTable.length,
|
1786 | end = start + length;
|
1787 | var format = font.getUint16();
|
1788 | var FORMAT_0_HEADER_LENGTH = 6;
|
1789 |
|
1790 | if (format !== 0 || length < FORMAT_0_HEADER_LENGTH) {
|
1791 | return names;
|
1792 | }
|
1793 |
|
1794 | var numRecords = font.getUint16();
|
1795 | var stringsStart = font.getUint16();
|
1796 | var records = [];
|
1797 | var NAME_RECORD_LENGTH = 12;
|
1798 | var i, ii;
|
1799 |
|
1800 | for (i = 0; i < numRecords && font.pos + NAME_RECORD_LENGTH <= end; i++) {
|
1801 | var r = {
|
1802 | platform: font.getUint16(),
|
1803 | encoding: font.getUint16(),
|
1804 | language: font.getUint16(),
|
1805 | name: font.getUint16(),
|
1806 | length: font.getUint16(),
|
1807 | offset: font.getUint16()
|
1808 | };
|
1809 |
|
1810 | if (r.platform === 1 && r.encoding === 0 && r.language === 0 || r.platform === 3 && r.encoding === 1 && r.language === 0x409) {
|
1811 | records.push(r);
|
1812 | }
|
1813 | }
|
1814 |
|
1815 | for (i = 0, ii = records.length; i < ii; i++) {
|
1816 | var record = records[i];
|
1817 |
|
1818 | if (record.length <= 0) {
|
1819 | continue;
|
1820 | }
|
1821 |
|
1822 | var pos = start + stringsStart + record.offset;
|
1823 |
|
1824 | if (pos + record.length > end) {
|
1825 | continue;
|
1826 | }
|
1827 |
|
1828 | font.pos = pos;
|
1829 | var nameIndex = record.name;
|
1830 |
|
1831 | if (record.encoding) {
|
1832 | var str = '';
|
1833 |
|
1834 | for (var j = 0, jj = record.length; j < jj; j += 2) {
|
1835 | str += String.fromCharCode(font.getUint16());
|
1836 | }
|
1837 |
|
1838 | names[1][nameIndex] = str;
|
1839 | } else {
|
1840 | names[0][nameIndex] = (0, _util.bytesToString)(font.getBytes(record.length));
|
1841 | }
|
1842 | }
|
1843 |
|
1844 | return names;
|
1845 | }
|
1846 |
|
1847 | var TTOpsStackDeltas = [0, 0, 0, 0, 0, 0, 0, 0, -2, -2, -2, -2, 0, 0, -2, -5, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, -1, 0, -1, -1, -1, -1, 1, -1, -999, 0, 1, 0, -1, -2, 0, -1, -2, -1, -1, 0, -1, -1, 0, 0, -999, -999, -1, -1, -1, -1, -2, -999, -2, -2, -999, 0, -2, -2, 0, 0, -2, 0, -2, 0, 0, 0, -2, -1, -1, 1, 1, 0, 0, -1, -1, -1, -1, -1, -1, -1, 0, 0, -1, 0, -1, -1, 0, -999, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, -999, -999, -999, -999, -999, -1, -1, -2, -2, 0, 0, 0, 0, -1, -1, -999, -2, -2, 0, 0, -1, -2, -2, 0, 0, 0, -1, -1, -1, -2];
|
1848 |
|
1849 | function sanitizeTTProgram(table, ttContext) {
|
1850 | var data = table.data;
|
1851 | var i = 0,
|
1852 | j,
|
1853 | n,
|
1854 | b,
|
1855 | funcId,
|
1856 | pc,
|
1857 | lastEndf = 0,
|
1858 | lastDeff = 0;
|
1859 | var stack = [];
|
1860 | var callstack = [];
|
1861 | var functionsCalled = [];
|
1862 | var tooComplexToFollowFunctions = ttContext.tooComplexToFollowFunctions;
|
1863 | var inFDEF = false,
|
1864 | ifLevel = 0,
|
1865 | inELSE = 0;
|
1866 |
|
1867 | for (var ii = data.length; i < ii;) {
|
1868 | var op = data[i++];
|
1869 |
|
1870 | if (op === 0x40) {
|
1871 | n = data[i++];
|
1872 |
|
1873 | if (inFDEF || inELSE) {
|
1874 | i += n;
|
1875 | } else {
|
1876 | for (j = 0; j < n; j++) {
|
1877 | stack.push(data[i++]);
|
1878 | }
|
1879 | }
|
1880 | } else if (op === 0x41) {
|
1881 | n = data[i++];
|
1882 |
|
1883 | if (inFDEF || inELSE) {
|
1884 | i += n * 2;
|
1885 | } else {
|
1886 | for (j = 0; j < n; j++) {
|
1887 | b = data[i++];
|
1888 | stack.push(b << 8 | data[i++]);
|
1889 | }
|
1890 | }
|
1891 | } else if ((op & 0xF8) === 0xB0) {
|
1892 | n = op - 0xB0 + 1;
|
1893 |
|
1894 | if (inFDEF || inELSE) {
|
1895 | i += n;
|
1896 | } else {
|
1897 | for (j = 0; j < n; j++) {
|
1898 | stack.push(data[i++]);
|
1899 | }
|
1900 | }
|
1901 | } else if ((op & 0xF8) === 0xB8) {
|
1902 | n = op - 0xB8 + 1;
|
1903 |
|
1904 | if (inFDEF || inELSE) {
|
1905 | i += n * 2;
|
1906 | } else {
|
1907 | for (j = 0; j < n; j++) {
|
1908 | b = data[i++];
|
1909 | stack.push(b << 8 | data[i++]);
|
1910 | }
|
1911 | }
|
1912 | } else if (op === 0x2B && !tooComplexToFollowFunctions) {
|
1913 | if (!inFDEF && !inELSE) {
|
1914 | funcId = stack[stack.length - 1];
|
1915 |
|
1916 | if (isNaN(funcId)) {
|
1917 | (0, _util.info)('TT: CALL empty stack (or invalid entry).');
|
1918 | } else {
|
1919 | ttContext.functionsUsed[funcId] = true;
|
1920 |
|
1921 | if (funcId in ttContext.functionsStackDeltas) {
|
1922 | var newStackLength = stack.length + ttContext.functionsStackDeltas[funcId];
|
1923 |
|
1924 | if (newStackLength < 0) {
|
1925 | (0, _util.warn)('TT: CALL invalid functions stack delta.');
|
1926 | ttContext.hintsValid = false;
|
1927 | return;
|
1928 | }
|
1929 |
|
1930 | stack.length = newStackLength;
|
1931 | } else if (funcId in ttContext.functionsDefined && !functionsCalled.includes(funcId)) {
|
1932 | callstack.push({
|
1933 | data: data,
|
1934 | i: i,
|
1935 | stackTop: stack.length - 1
|
1936 | });
|
1937 | functionsCalled.push(funcId);
|
1938 | pc = ttContext.functionsDefined[funcId];
|
1939 |
|
1940 | if (!pc) {
|
1941 | (0, _util.warn)('TT: CALL non-existent function');
|
1942 | ttContext.hintsValid = false;
|
1943 | return;
|
1944 | }
|
1945 |
|
1946 | data = pc.data;
|
1947 | i = pc.i;
|
1948 | }
|
1949 | }
|
1950 | }
|
1951 | } else if (op === 0x2C && !tooComplexToFollowFunctions) {
|
1952 | if (inFDEF || inELSE) {
|
1953 | (0, _util.warn)('TT: nested FDEFs not allowed');
|
1954 | tooComplexToFollowFunctions = true;
|
1955 | }
|
1956 |
|
1957 | inFDEF = true;
|
1958 | lastDeff = i;
|
1959 | funcId = stack.pop();
|
1960 | ttContext.functionsDefined[funcId] = {
|
1961 | data: data,
|
1962 | i: i
|
1963 | };
|
1964 | } else if (op === 0x2D) {
|
1965 | if (inFDEF) {
|
1966 | inFDEF = false;
|
1967 | lastEndf = i;
|
1968 | } else {
|
1969 | pc = callstack.pop();
|
1970 |
|
1971 | if (!pc) {
|
1972 | (0, _util.warn)('TT: ENDF bad stack');
|
1973 | ttContext.hintsValid = false;
|
1974 | return;
|
1975 | }
|
1976 |
|
1977 | funcId = functionsCalled.pop();
|
1978 | data = pc.data;
|
1979 | i = pc.i;
|
1980 | ttContext.functionsStackDeltas[funcId] = stack.length - pc.stackTop;
|
1981 | }
|
1982 | } else if (op === 0x89) {
|
1983 | if (inFDEF || inELSE) {
|
1984 | (0, _util.warn)('TT: nested IDEFs not allowed');
|
1985 | tooComplexToFollowFunctions = true;
|
1986 | }
|
1987 |
|
1988 | inFDEF = true;
|
1989 | lastDeff = i;
|
1990 | } else if (op === 0x58) {
|
1991 | ++ifLevel;
|
1992 | } else if (op === 0x1B) {
|
1993 | inELSE = ifLevel;
|
1994 | } else if (op === 0x59) {
|
1995 | if (inELSE === ifLevel) {
|
1996 | inELSE = 0;
|
1997 | }
|
1998 |
|
1999 | --ifLevel;
|
2000 | } else if (op === 0x1C) {
|
2001 | if (!inFDEF && !inELSE) {
|
2002 | var offset = stack[stack.length - 1];
|
2003 |
|
2004 | if (offset > 0) {
|
2005 | i += offset - 1;
|
2006 | }
|
2007 | }
|
2008 | }
|
2009 |
|
2010 | if (!inFDEF && !inELSE) {
|
2011 | var stackDelta = op <= 0x8E ? TTOpsStackDeltas[op] : op >= 0xC0 && op <= 0xDF ? -1 : op >= 0xE0 ? -2 : 0;
|
2012 |
|
2013 | if (op >= 0x71 && op <= 0x75) {
|
2014 | n = stack.pop();
|
2015 |
|
2016 | if (!isNaN(n)) {
|
2017 | stackDelta = -n * 2;
|
2018 | }
|
2019 | }
|
2020 |
|
2021 | while (stackDelta < 0 && stack.length > 0) {
|
2022 | stack.pop();
|
2023 | stackDelta++;
|
2024 | }
|
2025 |
|
2026 | while (stackDelta > 0) {
|
2027 | stack.push(NaN);
|
2028 | stackDelta--;
|
2029 | }
|
2030 | }
|
2031 | }
|
2032 |
|
2033 | ttContext.tooComplexToFollowFunctions = tooComplexToFollowFunctions;
|
2034 | var content = [data];
|
2035 |
|
2036 | if (i > data.length) {
|
2037 | content.push(new Uint8Array(i - data.length));
|
2038 | }
|
2039 |
|
2040 | if (lastDeff > lastEndf) {
|
2041 | (0, _util.warn)('TT: complementing a missing function tail');
|
2042 | content.push(new Uint8Array([0x22, 0x2D]));
|
2043 | }
|
2044 |
|
2045 | foldTTTable(table, content);
|
2046 | }
|
2047 |
|
2048 | function checkInvalidFunctions(ttContext, maxFunctionDefs) {
|
2049 | if (ttContext.tooComplexToFollowFunctions) {
|
2050 | return;
|
2051 | }
|
2052 |
|
2053 | if (ttContext.functionsDefined.length > maxFunctionDefs) {
|
2054 | (0, _util.warn)('TT: more functions defined than expected');
|
2055 | ttContext.hintsValid = false;
|
2056 | return;
|
2057 | }
|
2058 |
|
2059 | for (var j = 0, jj = ttContext.functionsUsed.length; j < jj; j++) {
|
2060 | if (j > maxFunctionDefs) {
|
2061 | (0, _util.warn)('TT: invalid function id: ' + j);
|
2062 | ttContext.hintsValid = false;
|
2063 | return;
|
2064 | }
|
2065 |
|
2066 | if (ttContext.functionsUsed[j] && !ttContext.functionsDefined[j]) {
|
2067 | (0, _util.warn)('TT: undefined function: ' + j);
|
2068 | ttContext.hintsValid = false;
|
2069 | return;
|
2070 | }
|
2071 | }
|
2072 | }
|
2073 |
|
2074 | function foldTTTable(table, content) {
|
2075 | if (content.length > 1) {
|
2076 | var newLength = 0;
|
2077 | var j, jj;
|
2078 |
|
2079 | for (j = 0, jj = content.length; j < jj; j++) {
|
2080 | newLength += content[j].length;
|
2081 | }
|
2082 |
|
2083 | newLength = newLength + 3 & ~3;
|
2084 | var result = new Uint8Array(newLength);
|
2085 | var pos = 0;
|
2086 |
|
2087 | for (j = 0, jj = content.length; j < jj; j++) {
|
2088 | result.set(content[j], pos);
|
2089 | pos += content[j].length;
|
2090 | }
|
2091 |
|
2092 | table.data = result;
|
2093 | table.length = newLength;
|
2094 | }
|
2095 | }
|
2096 |
|
2097 | function sanitizeTTPrograms(fpgm, prep, cvt, maxFunctionDefs) {
|
2098 | var ttContext = {
|
2099 | functionsDefined: [],
|
2100 | functionsUsed: [],
|
2101 | functionsStackDeltas: [],
|
2102 | tooComplexToFollowFunctions: false,
|
2103 | hintsValid: true
|
2104 | };
|
2105 |
|
2106 | if (fpgm) {
|
2107 | sanitizeTTProgram(fpgm, ttContext);
|
2108 | }
|
2109 |
|
2110 | if (prep) {
|
2111 | sanitizeTTProgram(prep, ttContext);
|
2112 | }
|
2113 |
|
2114 | if (fpgm) {
|
2115 | checkInvalidFunctions(ttContext, maxFunctionDefs);
|
2116 | }
|
2117 |
|
2118 | if (cvt && cvt.length & 1) {
|
2119 | var cvtData = new Uint8Array(cvt.length + 1);
|
2120 | cvtData.set(cvt.data);
|
2121 | cvt.data = cvtData;
|
2122 | }
|
2123 |
|
2124 | return ttContext.hintsValid;
|
2125 | }
|
2126 |
|
2127 | font = new _stream.Stream(new Uint8Array(font.getBytes()));
|
2128 | var header, tables;
|
2129 |
|
2130 | if (isTrueTypeCollectionFile(font)) {
|
2131 | var ttcData = readTrueTypeCollectionData(font, this.name);
|
2132 | header = ttcData.header;
|
2133 | tables = ttcData.tables;
|
2134 | } else {
|
2135 | header = readOpenTypeHeader(font);
|
2136 | tables = readTables(font, header.numTables);
|
2137 | }
|
2138 |
|
2139 | var cff, cffFile;
|
2140 | var isTrueType = !tables['CFF '];
|
2141 |
|
2142 | if (!isTrueType) {
|
2143 | var isComposite = properties.composite && ((properties.cidToGidMap || []).length > 0 || !(properties.cMap instanceof _cmap.IdentityCMap));
|
2144 |
|
2145 | if (header.version === 'OTTO' && !isComposite || !tables['head'] || !tables['hhea'] || !tables['maxp'] || !tables['post']) {
|
2146 | cffFile = new _stream.Stream(tables['CFF '].data);
|
2147 | cff = new CFFFont(cffFile, properties);
|
2148 | adjustWidths(properties);
|
2149 | return this.convert(name, cff, properties);
|
2150 | }
|
2151 |
|
2152 | delete tables['glyf'];
|
2153 | delete tables['loca'];
|
2154 | delete tables['fpgm'];
|
2155 | delete tables['prep'];
|
2156 | delete tables['cvt '];
|
2157 | this.isOpenType = true;
|
2158 | } else {
|
2159 | if (!tables['loca']) {
|
2160 | throw new _util.FormatError('Required "loca" table is not found');
|
2161 | }
|
2162 |
|
2163 | if (!tables['glyf']) {
|
2164 | (0, _util.warn)('Required "glyf" table is not found -- trying to recover.');
|
2165 | tables['glyf'] = {
|
2166 | tag: 'glyf',
|
2167 | data: new Uint8Array(0)
|
2168 | };
|
2169 | }
|
2170 |
|
2171 | this.isOpenType = false;
|
2172 | }
|
2173 |
|
2174 | if (!tables['maxp']) {
|
2175 | throw new _util.FormatError('Required "maxp" table is not found');
|
2176 | }
|
2177 |
|
2178 | font.pos = (font.start || 0) + tables['maxp'].offset;
|
2179 | var version = font.getInt32();
|
2180 | var numGlyphs = font.getUint16();
|
2181 | var numGlyphsOut = numGlyphs + 1;
|
2182 | var dupFirstEntry = true;
|
2183 |
|
2184 | if (numGlyphsOut > 0xFFFF) {
|
2185 | dupFirstEntry = false;
|
2186 | numGlyphsOut = numGlyphs;
|
2187 | (0, _util.warn)('Not enough space in glyfs to duplicate first glyph.');
|
2188 | }
|
2189 |
|
2190 | var maxFunctionDefs = 0;
|
2191 | var maxSizeOfInstructions = 0;
|
2192 |
|
2193 | if (version >= 0x00010000 && tables['maxp'].length >= 22) {
|
2194 | font.pos += 8;
|
2195 | var maxZones = font.getUint16();
|
2196 |
|
2197 | if (maxZones > 2) {
|
2198 | tables['maxp'].data[14] = 0;
|
2199 | tables['maxp'].data[15] = 2;
|
2200 | }
|
2201 |
|
2202 | font.pos += 4;
|
2203 | maxFunctionDefs = font.getUint16();
|
2204 | font.pos += 4;
|
2205 | maxSizeOfInstructions = font.getUint16();
|
2206 | }
|
2207 |
|
2208 | tables['maxp'].data[4] = numGlyphsOut >> 8;
|
2209 | tables['maxp'].data[5] = numGlyphsOut & 255;
|
2210 | var hintsValid = sanitizeTTPrograms(tables['fpgm'], tables['prep'], tables['cvt '], maxFunctionDefs);
|
2211 |
|
2212 | if (!hintsValid) {
|
2213 | delete tables['fpgm'];
|
2214 | delete tables['prep'];
|
2215 | delete tables['cvt '];
|
2216 | }
|
2217 |
|
2218 | sanitizeMetrics(font, tables['hhea'], tables['hmtx'], numGlyphsOut);
|
2219 |
|
2220 | if (!tables['head']) {
|
2221 | throw new _util.FormatError('Required "head" table is not found');
|
2222 | }
|
2223 |
|
2224 | sanitizeHead(tables['head'], numGlyphs, isTrueType ? tables['loca'].length : 0);
|
2225 | var missingGlyphs = Object.create(null);
|
2226 |
|
2227 | if (isTrueType) {
|
2228 | var isGlyphLocationsLong = int16(tables['head'].data[50], tables['head'].data[51]);
|
2229 | var glyphsInfo = sanitizeGlyphLocations(tables['loca'], tables['glyf'], numGlyphs, isGlyphLocationsLong, hintsValid, dupFirstEntry, maxSizeOfInstructions);
|
2230 | missingGlyphs = glyphsInfo.missingGlyphs;
|
2231 |
|
2232 | if (version >= 0x00010000 && tables['maxp'].length >= 22) {
|
2233 | tables['maxp'].data[26] = glyphsInfo.maxSizeOfInstructions >> 8;
|
2234 | tables['maxp'].data[27] = glyphsInfo.maxSizeOfInstructions & 255;
|
2235 | }
|
2236 | }
|
2237 |
|
2238 | if (!tables['hhea']) {
|
2239 | throw new _util.FormatError('Required "hhea" table is not found');
|
2240 | }
|
2241 |
|
2242 | if (tables['hhea'].data[10] === 0 && tables['hhea'].data[11] === 0) {
|
2243 | tables['hhea'].data[10] = 0xFF;
|
2244 | tables['hhea'].data[11] = 0xFF;
|
2245 | }
|
2246 |
|
2247 | var metricsOverride = {
|
2248 | unitsPerEm: int16(tables['head'].data[18], tables['head'].data[19]),
|
2249 | yMax: int16(tables['head'].data[42], tables['head'].data[43]),
|
2250 | yMin: signedInt16(tables['head'].data[38], tables['head'].data[39]),
|
2251 | ascent: int16(tables['hhea'].data[4], tables['hhea'].data[5]),
|
2252 | descent: signedInt16(tables['hhea'].data[6], tables['hhea'].data[7])
|
2253 | };
|
2254 | this.ascent = metricsOverride.ascent / metricsOverride.unitsPerEm;
|
2255 | this.descent = metricsOverride.descent / metricsOverride.unitsPerEm;
|
2256 |
|
2257 | if (tables['post']) {
|
2258 | readPostScriptTable(tables['post'], properties, numGlyphs);
|
2259 | }
|
2260 |
|
2261 | tables['post'] = {
|
2262 | tag: 'post',
|
2263 | data: createPostTable(properties)
|
2264 | };
|
2265 | var charCodeToGlyphId = [],
|
2266 | charCode;
|
2267 |
|
2268 | function hasGlyph(glyphId) {
|
2269 | return !missingGlyphs[glyphId];
|
2270 | }
|
2271 |
|
2272 | if (properties.composite) {
|
2273 | var cidToGidMap = properties.cidToGidMap || [];
|
2274 | var isCidToGidMapEmpty = cidToGidMap.length === 0;
|
2275 | properties.cMap.forEach(function (charCode, cid) {
|
2276 | if (cid > 0xffff) {
|
2277 | throw new _util.FormatError('Max size of CID is 65,535');
|
2278 | }
|
2279 |
|
2280 | var glyphId = -1;
|
2281 |
|
2282 | if (isCidToGidMapEmpty) {
|
2283 | glyphId = cid;
|
2284 | } else if (cidToGidMap[cid] !== undefined) {
|
2285 | glyphId = cidToGidMap[cid];
|
2286 | }
|
2287 |
|
2288 | if (glyphId >= 0 && glyphId < numGlyphs && hasGlyph(glyphId)) {
|
2289 | charCodeToGlyphId[charCode] = glyphId;
|
2290 | }
|
2291 | });
|
2292 | } else {
|
2293 | var cmapTable = readCmapTable(tables['cmap'], font, this.isSymbolicFont, properties.hasEncoding);
|
2294 | var cmapPlatformId = cmapTable.platformId;
|
2295 | var cmapEncodingId = cmapTable.encodingId;
|
2296 | var cmapMappings = cmapTable.mappings;
|
2297 | var cmapMappingsLength = cmapMappings.length;
|
2298 |
|
2299 | if (properties.hasEncoding && (cmapPlatformId === 3 && cmapEncodingId === 1 || cmapPlatformId === 1 && cmapEncodingId === 0) || cmapPlatformId === -1 && cmapEncodingId === -1 && !!(0, _encodings.getEncoding)(properties.baseEncodingName)) {
|
2300 | var baseEncoding = [];
|
2301 |
|
2302 | if (properties.baseEncodingName === 'MacRomanEncoding' || properties.baseEncodingName === 'WinAnsiEncoding') {
|
2303 | baseEncoding = (0, _encodings.getEncoding)(properties.baseEncodingName);
|
2304 | }
|
2305 |
|
2306 | var glyphsUnicodeMap = (0, _glyphlist.getGlyphsUnicode)();
|
2307 |
|
2308 | for (charCode = 0; charCode < 256; charCode++) {
|
2309 | var glyphName, standardGlyphName;
|
2310 |
|
2311 | if (this.differences && charCode in this.differences) {
|
2312 | glyphName = this.differences[charCode];
|
2313 | } else if (charCode in baseEncoding && baseEncoding[charCode] !== '') {
|
2314 | glyphName = baseEncoding[charCode];
|
2315 | } else {
|
2316 | glyphName = _encodings.StandardEncoding[charCode];
|
2317 | }
|
2318 |
|
2319 | if (!glyphName) {
|
2320 | continue;
|
2321 | }
|
2322 |
|
2323 | standardGlyphName = recoverGlyphName(glyphName, glyphsUnicodeMap);
|
2324 | var unicodeOrCharCode;
|
2325 |
|
2326 | if (cmapPlatformId === 3 && cmapEncodingId === 1) {
|
2327 | unicodeOrCharCode = glyphsUnicodeMap[standardGlyphName];
|
2328 | } else if (cmapPlatformId === 1 && cmapEncodingId === 0) {
|
2329 | unicodeOrCharCode = _encodings.MacRomanEncoding.indexOf(standardGlyphName);
|
2330 | }
|
2331 |
|
2332 | var found = false;
|
2333 |
|
2334 | for (var i = 0; i < cmapMappingsLength; ++i) {
|
2335 | if (cmapMappings[i].charCode !== unicodeOrCharCode) {
|
2336 | continue;
|
2337 | }
|
2338 |
|
2339 | charCodeToGlyphId[charCode] = cmapMappings[i].glyphId;
|
2340 | found = true;
|
2341 | break;
|
2342 | }
|
2343 |
|
2344 | if (!found && properties.glyphNames) {
|
2345 | var glyphId = properties.glyphNames.indexOf(glyphName);
|
2346 |
|
2347 | if (glyphId === -1 && standardGlyphName !== glyphName) {
|
2348 | glyphId = properties.glyphNames.indexOf(standardGlyphName);
|
2349 | }
|
2350 |
|
2351 | if (glyphId > 0 && hasGlyph(glyphId)) {
|
2352 | charCodeToGlyphId[charCode] = glyphId;
|
2353 | }
|
2354 | }
|
2355 | }
|
2356 | } else if (cmapPlatformId === 0 && cmapEncodingId === 0) {
|
2357 | for (var _i2 = 0; _i2 < cmapMappingsLength; ++_i2) {
|
2358 | charCodeToGlyphId[cmapMappings[_i2].charCode] = cmapMappings[_i2].glyphId;
|
2359 | }
|
2360 | } else {
|
2361 | for (var _i3 = 0; _i3 < cmapMappingsLength; ++_i3) {
|
2362 | charCode = cmapMappings[_i3].charCode;
|
2363 |
|
2364 | if (cmapPlatformId === 3 && charCode >= 0xF000 && charCode <= 0xF0FF) {
|
2365 | charCode &= 0xFF;
|
2366 | }
|
2367 |
|
2368 | charCodeToGlyphId[charCode] = cmapMappings[_i3].glyphId;
|
2369 | }
|
2370 | }
|
2371 | }
|
2372 |
|
2373 | if (charCodeToGlyphId.length === 0) {
|
2374 | charCodeToGlyphId[0] = 0;
|
2375 | }
|
2376 |
|
2377 | var glyphZeroId = numGlyphsOut - 1;
|
2378 |
|
2379 | if (!dupFirstEntry) {
|
2380 | glyphZeroId = 0;
|
2381 | }
|
2382 |
|
2383 | var newMapping = adjustMapping(charCodeToGlyphId, hasGlyph, glyphZeroId);
|
2384 | this.toFontChar = newMapping.toFontChar;
|
2385 | tables['cmap'] = {
|
2386 | tag: 'cmap',
|
2387 | data: createCmapTable(newMapping.charCodeToGlyphId, numGlyphsOut)
|
2388 | };
|
2389 |
|
2390 | if (!tables['OS/2'] || !validateOS2Table(tables['OS/2'])) {
|
2391 | tables['OS/2'] = {
|
2392 | tag: 'OS/2',
|
2393 | data: createOS2Table(properties, newMapping.charCodeToGlyphId, metricsOverride)
|
2394 | };
|
2395 | }
|
2396 |
|
2397 | if (!isTrueType) {
|
2398 | try {
|
2399 | cffFile = new _stream.Stream(tables['CFF '].data);
|
2400 | var parser = new _cff_parser.CFFParser(cffFile, properties, SEAC_ANALYSIS_ENABLED);
|
2401 | cff = parser.parse();
|
2402 | cff.duplicateFirstGlyph();
|
2403 | var compiler = new _cff_parser.CFFCompiler(cff);
|
2404 | tables['CFF '].data = compiler.compile();
|
2405 | } catch (e) {
|
2406 | (0, _util.warn)('Failed to compile font ' + properties.loadedName);
|
2407 | }
|
2408 | }
|
2409 |
|
2410 | if (!tables['name']) {
|
2411 | tables['name'] = {
|
2412 | tag: 'name',
|
2413 | data: createNameTable(this.name)
|
2414 | };
|
2415 | } else {
|
2416 | var namePrototype = readNameTable(tables['name']);
|
2417 | tables['name'].data = createNameTable(name, namePrototype);
|
2418 | }
|
2419 |
|
2420 | var builder = new OpenTypeFileBuilder(header.version);
|
2421 |
|
2422 | for (var tableTag in tables) {
|
2423 | builder.addTable(tableTag, tables[tableTag].data);
|
2424 | }
|
2425 |
|
2426 | return builder.toArray();
|
2427 | },
|
2428 | convert: function Font_convert(fontName, font, properties) {
|
2429 | properties.fixedPitch = false;
|
2430 |
|
2431 | if (properties.builtInEncoding) {
|
2432 | adjustToUnicode(properties, properties.builtInEncoding);
|
2433 | }
|
2434 |
|
2435 | var glyphZeroId = 1;
|
2436 |
|
2437 | if (font instanceof CFFFont) {
|
2438 | glyphZeroId = font.numGlyphs - 1;
|
2439 | }
|
2440 |
|
2441 | var mapping = font.getGlyphMapping(properties);
|
2442 | var newMapping = adjustMapping(mapping, font.hasGlyphId.bind(font), glyphZeroId);
|
2443 | this.toFontChar = newMapping.toFontChar;
|
2444 | var numGlyphs = font.numGlyphs;
|
2445 |
|
2446 | function getCharCodes(charCodeToGlyphId, glyphId) {
|
2447 | var charCodes = null;
|
2448 |
|
2449 | for (var charCode in charCodeToGlyphId) {
|
2450 | if (glyphId === charCodeToGlyphId[charCode]) {
|
2451 | if (!charCodes) {
|
2452 | charCodes = [];
|
2453 | }
|
2454 |
|
2455 | charCodes.push(charCode | 0);
|
2456 | }
|
2457 | }
|
2458 |
|
2459 | return charCodes;
|
2460 | }
|
2461 |
|
2462 | function createCharCode(charCodeToGlyphId, glyphId) {
|
2463 | for (var charCode in charCodeToGlyphId) {
|
2464 | if (glyphId === charCodeToGlyphId[charCode]) {
|
2465 | return charCode | 0;
|
2466 | }
|
2467 | }
|
2468 |
|
2469 | newMapping.charCodeToGlyphId[newMapping.nextAvailableFontCharCode] = glyphId;
|
2470 | return newMapping.nextAvailableFontCharCode++;
|
2471 | }
|
2472 |
|
2473 | var seacs = font.seacs;
|
2474 |
|
2475 | if (SEAC_ANALYSIS_ENABLED && seacs && seacs.length) {
|
2476 | var matrix = properties.fontMatrix || _util.FONT_IDENTITY_MATRIX;
|
2477 | var charset = font.getCharset();
|
2478 | var seacMap = Object.create(null);
|
2479 |
|
2480 | for (var glyphId in seacs) {
|
2481 | glyphId |= 0;
|
2482 | var seac = seacs[glyphId];
|
2483 | var baseGlyphName = _encodings.StandardEncoding[seac[2]];
|
2484 | var accentGlyphName = _encodings.StandardEncoding[seac[3]];
|
2485 | var baseGlyphId = charset.indexOf(baseGlyphName);
|
2486 | var accentGlyphId = charset.indexOf(accentGlyphName);
|
2487 |
|
2488 | if (baseGlyphId < 0 || accentGlyphId < 0) {
|
2489 | continue;
|
2490 | }
|
2491 |
|
2492 | var accentOffset = {
|
2493 | x: seac[0] * matrix[0] + seac[1] * matrix[2] + matrix[4],
|
2494 | y: seac[0] * matrix[1] + seac[1] * matrix[3] + matrix[5]
|
2495 | };
|
2496 | var charCodes = getCharCodes(mapping, glyphId);
|
2497 |
|
2498 | if (!charCodes) {
|
2499 | continue;
|
2500 | }
|
2501 |
|
2502 | for (var i = 0, ii = charCodes.length; i < ii; i++) {
|
2503 | var charCode = charCodes[i];
|
2504 | var charCodeToGlyphId = newMapping.charCodeToGlyphId;
|
2505 | var baseFontCharCode = createCharCode(charCodeToGlyphId, baseGlyphId);
|
2506 | var accentFontCharCode = createCharCode(charCodeToGlyphId, accentGlyphId);
|
2507 | seacMap[charCode] = {
|
2508 | baseFontCharCode: baseFontCharCode,
|
2509 | accentFontCharCode: accentFontCharCode,
|
2510 | accentOffset: accentOffset
|
2511 | };
|
2512 | }
|
2513 | }
|
2514 |
|
2515 | properties.seacMap = seacMap;
|
2516 | }
|
2517 |
|
2518 | var unitsPerEm = 1 / (properties.fontMatrix || _util.FONT_IDENTITY_MATRIX)[0];
|
2519 | var builder = new OpenTypeFileBuilder('\x4F\x54\x54\x4F');
|
2520 | builder.addTable('CFF ', font.data);
|
2521 | builder.addTable('OS/2', createOS2Table(properties, newMapping.charCodeToGlyphId));
|
2522 | builder.addTable('cmap', createCmapTable(newMapping.charCodeToGlyphId, numGlyphs));
|
2523 | builder.addTable('head', '\x00\x01\x00\x00' + '\x00\x00\x10\x00' + '\x00\x00\x00\x00' + '\x5F\x0F\x3C\xF5' + '\x00\x00' + safeString16(unitsPerEm) + '\x00\x00\x00\x00\x9e\x0b\x7e\x27' + '\x00\x00\x00\x00\x9e\x0b\x7e\x27' + '\x00\x00' + safeString16(properties.descent) + '\x0F\xFF' + safeString16(properties.ascent) + string16(properties.italicAngle ? 2 : 0) + '\x00\x11' + '\x00\x00' + '\x00\x00' + '\x00\x00');
|
2524 | builder.addTable('hhea', '\x00\x01\x00\x00' + safeString16(properties.ascent) + safeString16(properties.descent) + '\x00\x00' + '\xFF\xFF' + '\x00\x00' + '\x00\x00' + '\x00\x00' + safeString16(properties.capHeight) + safeString16(Math.tan(properties.italicAngle) * properties.xHeight) + '\x00\x00' + '\x00\x00' + '\x00\x00' + '\x00\x00' + '\x00\x00' + '\x00\x00' + string16(numGlyphs));
|
2525 | builder.addTable('hmtx', function fontFieldsHmtx() {
|
2526 | var charstrings = font.charstrings;
|
2527 | var cffWidths = font.cff ? font.cff.widths : null;
|
2528 | var hmtx = '\x00\x00\x00\x00';
|
2529 |
|
2530 | for (var i = 1, ii = numGlyphs; i < ii; i++) {
|
2531 | var width = 0;
|
2532 |
|
2533 | if (charstrings) {
|
2534 | var charstring = charstrings[i - 1];
|
2535 | width = 'width' in charstring ? charstring.width : 0;
|
2536 | } else if (cffWidths) {
|
2537 | width = Math.ceil(cffWidths[i] || 0);
|
2538 | }
|
2539 |
|
2540 | hmtx += string16(width) + string16(0);
|
2541 | }
|
2542 |
|
2543 | return hmtx;
|
2544 | }());
|
2545 | builder.addTable('maxp', '\x00\x00\x50\x00' + string16(numGlyphs));
|
2546 | builder.addTable('name', createNameTable(fontName));
|
2547 | builder.addTable('post', createPostTable(properties));
|
2548 | return builder.toArray();
|
2549 | },
|
2550 |
|
2551 | get spaceWidth() {
|
2552 | if ('_shadowWidth' in this) {
|
2553 | return this._shadowWidth;
|
2554 | }
|
2555 |
|
2556 | var possibleSpaceReplacements = ['space', 'minus', 'one', 'i', 'I'];
|
2557 | var width;
|
2558 |
|
2559 | for (var i = 0, ii = possibleSpaceReplacements.length; i < ii; i++) {
|
2560 | var glyphName = possibleSpaceReplacements[i];
|
2561 |
|
2562 | if (glyphName in this.widths) {
|
2563 | width = this.widths[glyphName];
|
2564 | break;
|
2565 | }
|
2566 |
|
2567 | var glyphsUnicodeMap = (0, _glyphlist.getGlyphsUnicode)();
|
2568 | var glyphUnicode = glyphsUnicodeMap[glyphName];
|
2569 | var charcode = 0;
|
2570 |
|
2571 | if (this.composite) {
|
2572 | if (this.cMap.contains(glyphUnicode)) {
|
2573 | charcode = this.cMap.lookup(glyphUnicode);
|
2574 | }
|
2575 | }
|
2576 |
|
2577 | if (!charcode && this.toUnicode) {
|
2578 | charcode = this.toUnicode.charCodeOf(glyphUnicode);
|
2579 | }
|
2580 |
|
2581 | if (charcode <= 0) {
|
2582 | charcode = glyphUnicode;
|
2583 | }
|
2584 |
|
2585 | width = this.widths[charcode];
|
2586 |
|
2587 | if (width) {
|
2588 | break;
|
2589 | }
|
2590 | }
|
2591 |
|
2592 | width = width || this.defaultWidth;
|
2593 | this._shadowWidth = width;
|
2594 | return width;
|
2595 | },
|
2596 |
|
2597 | charToGlyph: function Font_charToGlyph(charcode, isSpace) {
|
2598 | var fontCharCode, width, operatorListId;
|
2599 | var widthCode = charcode;
|
2600 |
|
2601 | if (this.cMap && this.cMap.contains(charcode)) {
|
2602 | widthCode = this.cMap.lookup(charcode);
|
2603 | }
|
2604 |
|
2605 | width = this.widths[widthCode];
|
2606 | width = (0, _util.isNum)(width) ? width : this.defaultWidth;
|
2607 | var vmetric = this.vmetrics && this.vmetrics[widthCode];
|
2608 | var unicode = this.toUnicode.get(charcode) || this.fallbackToUnicode.get(charcode) || charcode;
|
2609 |
|
2610 | if (typeof unicode === 'number') {
|
2611 | unicode = String.fromCharCode(unicode);
|
2612 | }
|
2613 |
|
2614 | var isInFont = charcode in this.toFontChar;
|
2615 | fontCharCode = this.toFontChar[charcode] || charcode;
|
2616 |
|
2617 | if (this.missingFile) {
|
2618 | fontCharCode = (0, _unicode.mapSpecialUnicodeValues)(fontCharCode);
|
2619 | }
|
2620 |
|
2621 | if (this.isType3Font) {
|
2622 | operatorListId = fontCharCode;
|
2623 | }
|
2624 |
|
2625 | var accent = null;
|
2626 |
|
2627 | if (this.seacMap && this.seacMap[charcode]) {
|
2628 | isInFont = true;
|
2629 | var seac = this.seacMap[charcode];
|
2630 | fontCharCode = seac.baseFontCharCode;
|
2631 | accent = {
|
2632 | fontChar: String.fromCodePoint(seac.accentFontCharCode),
|
2633 | offset: seac.accentOffset
|
2634 | };
|
2635 | }
|
2636 |
|
2637 | var fontChar = typeof fontCharCode === 'number' ? String.fromCodePoint(fontCharCode) : '';
|
2638 | var glyph = this.glyphCache[charcode];
|
2639 |
|
2640 | if (!glyph || !glyph.matchesForCache(fontChar, unicode, accent, width, vmetric, operatorListId, isSpace, isInFont)) {
|
2641 | glyph = new Glyph(fontChar, unicode, accent, width, vmetric, operatorListId, isSpace, isInFont);
|
2642 | this.glyphCache[charcode] = glyph;
|
2643 | }
|
2644 |
|
2645 | return glyph;
|
2646 | },
|
2647 | charsToGlyphs: function Font_charsToGlyphs(chars) {
|
2648 | var charsCache = this.charsCache;
|
2649 | var glyphs, glyph, charcode;
|
2650 |
|
2651 | if (charsCache) {
|
2652 | glyphs = charsCache[chars];
|
2653 |
|
2654 | if (glyphs) {
|
2655 | return glyphs;
|
2656 | }
|
2657 | }
|
2658 |
|
2659 | if (!charsCache) {
|
2660 | charsCache = this.charsCache = Object.create(null);
|
2661 | }
|
2662 |
|
2663 | glyphs = [];
|
2664 | var charsCacheKey = chars;
|
2665 | var i = 0,
|
2666 | ii;
|
2667 |
|
2668 | if (this.cMap) {
|
2669 | var c = Object.create(null);
|
2670 |
|
2671 | while (i < chars.length) {
|
2672 | this.cMap.readCharCode(chars, i, c);
|
2673 | charcode = c.charcode;
|
2674 | var length = c.length;
|
2675 | i += length;
|
2676 | var isSpace = length === 1 && chars.charCodeAt(i - 1) === 0x20;
|
2677 | glyph = this.charToGlyph(charcode, isSpace);
|
2678 | glyphs.push(glyph);
|
2679 | }
|
2680 | } else {
|
2681 | for (i = 0, ii = chars.length; i < ii; ++i) {
|
2682 | charcode = chars.charCodeAt(i);
|
2683 | glyph = this.charToGlyph(charcode, charcode === 0x20);
|
2684 | glyphs.push(glyph);
|
2685 | }
|
2686 | }
|
2687 |
|
2688 | return charsCache[charsCacheKey] = glyphs;
|
2689 | },
|
2690 |
|
2691 | get glyphCacheValues() {
|
2692 | return Object.values(this.glyphCache);
|
2693 | }
|
2694 |
|
2695 | };
|
2696 | return Font;
|
2697 | }();
|
2698 |
|
2699 | exports.Font = Font;
|
2700 |
|
2701 | var ErrorFont = function ErrorFontClosure() {
|
2702 | function ErrorFont(error) {
|
2703 | this.error = error;
|
2704 | this.loadedName = 'g_font_error';
|
2705 | this.missingFile = true;
|
2706 | }
|
2707 |
|
2708 | ErrorFont.prototype = {
|
2709 | charsToGlyphs: function ErrorFont_charsToGlyphs() {
|
2710 | return [];
|
2711 | },
|
2712 | exportData: function ErrorFont_exportData() {
|
2713 | return {
|
2714 | error: this.error
|
2715 | };
|
2716 | }
|
2717 | };
|
2718 | return ErrorFont;
|
2719 | }();
|
2720 |
|
2721 | exports.ErrorFont = ErrorFont;
|
2722 |
|
2723 | function type1FontGlyphMapping(properties, builtInEncoding, glyphNames) {
|
2724 | var charCodeToGlyphId = Object.create(null);
|
2725 | var glyphId, charCode, baseEncoding;
|
2726 | var isSymbolicFont = !!(properties.flags & FontFlags.Symbolic);
|
2727 |
|
2728 | if (properties.baseEncodingName) {
|
2729 | baseEncoding = (0, _encodings.getEncoding)(properties.baseEncodingName);
|
2730 |
|
2731 | for (charCode = 0; charCode < baseEncoding.length; charCode++) {
|
2732 | glyphId = glyphNames.indexOf(baseEncoding[charCode]);
|
2733 |
|
2734 | if (glyphId >= 0) {
|
2735 | charCodeToGlyphId[charCode] = glyphId;
|
2736 | } else {
|
2737 | charCodeToGlyphId[charCode] = 0;
|
2738 | }
|
2739 | }
|
2740 | } else if (isSymbolicFont) {
|
2741 | for (charCode in builtInEncoding) {
|
2742 | charCodeToGlyphId[charCode] = builtInEncoding[charCode];
|
2743 | }
|
2744 | } else {
|
2745 | baseEncoding = _encodings.StandardEncoding;
|
2746 |
|
2747 | for (charCode = 0; charCode < baseEncoding.length; charCode++) {
|
2748 | glyphId = glyphNames.indexOf(baseEncoding[charCode]);
|
2749 |
|
2750 | if (glyphId >= 0) {
|
2751 | charCodeToGlyphId[charCode] = glyphId;
|
2752 | } else {
|
2753 | charCodeToGlyphId[charCode] = 0;
|
2754 | }
|
2755 | }
|
2756 | }
|
2757 |
|
2758 | var differences = properties.differences,
|
2759 | glyphsUnicodeMap;
|
2760 |
|
2761 | if (differences) {
|
2762 | for (charCode in differences) {
|
2763 | var glyphName = differences[charCode];
|
2764 | glyphId = glyphNames.indexOf(glyphName);
|
2765 |
|
2766 | if (glyphId === -1) {
|
2767 | if (!glyphsUnicodeMap) {
|
2768 | glyphsUnicodeMap = (0, _glyphlist.getGlyphsUnicode)();
|
2769 | }
|
2770 |
|
2771 | var standardGlyphName = recoverGlyphName(glyphName, glyphsUnicodeMap);
|
2772 |
|
2773 | if (standardGlyphName !== glyphName) {
|
2774 | glyphId = glyphNames.indexOf(standardGlyphName);
|
2775 | }
|
2776 | }
|
2777 |
|
2778 | if (glyphId >= 0) {
|
2779 | charCodeToGlyphId[charCode] = glyphId;
|
2780 | } else {
|
2781 | charCodeToGlyphId[charCode] = 0;
|
2782 | }
|
2783 | }
|
2784 | }
|
2785 |
|
2786 | return charCodeToGlyphId;
|
2787 | }
|
2788 |
|
2789 | var Type1Font = function Type1FontClosure() {
|
2790 | function findBlock(streamBytes, signature, startIndex) {
|
2791 | var streamBytesLength = streamBytes.length;
|
2792 | var signatureLength = signature.length;
|
2793 | var scanLength = streamBytesLength - signatureLength;
|
2794 | var i = startIndex,
|
2795 | j,
|
2796 | found = false;
|
2797 |
|
2798 | while (i < scanLength) {
|
2799 | j = 0;
|
2800 |
|
2801 | while (j < signatureLength && streamBytes[i + j] === signature[j]) {
|
2802 | j++;
|
2803 | }
|
2804 |
|
2805 | if (j >= signatureLength) {
|
2806 | i += j;
|
2807 |
|
2808 | while (i < streamBytesLength && (0, _util.isSpace)(streamBytes[i])) {
|
2809 | i++;
|
2810 | }
|
2811 |
|
2812 | found = true;
|
2813 | break;
|
2814 | }
|
2815 |
|
2816 | i++;
|
2817 | }
|
2818 |
|
2819 | return {
|
2820 | found: found,
|
2821 | length: i
|
2822 | };
|
2823 | }
|
2824 |
|
2825 | function getHeaderBlock(stream, suggestedLength) {
|
2826 | var EEXEC_SIGNATURE = [0x65, 0x65, 0x78, 0x65, 0x63];
|
2827 | var streamStartPos = stream.pos;
|
2828 | var headerBytes, headerBytesLength, block;
|
2829 |
|
2830 | try {
|
2831 | headerBytes = stream.getBytes(suggestedLength);
|
2832 | headerBytesLength = headerBytes.length;
|
2833 | } catch (ex) {
|
2834 | if (ex instanceof _util.MissingDataException) {
|
2835 | throw ex;
|
2836 | }
|
2837 | }
|
2838 |
|
2839 | if (headerBytesLength === suggestedLength) {
|
2840 | block = findBlock(headerBytes, EEXEC_SIGNATURE, suggestedLength - 2 * EEXEC_SIGNATURE.length);
|
2841 |
|
2842 | if (block.found && block.length === suggestedLength) {
|
2843 | return {
|
2844 | stream: new _stream.Stream(headerBytes),
|
2845 | length: suggestedLength
|
2846 | };
|
2847 | }
|
2848 | }
|
2849 |
|
2850 | (0, _util.warn)('Invalid "Length1" property in Type1 font -- trying to recover.');
|
2851 | stream.pos = streamStartPos;
|
2852 | var SCAN_BLOCK_LENGTH = 2048;
|
2853 | var actualLength;
|
2854 |
|
2855 | while (true) {
|
2856 | var scanBytes = stream.peekBytes(SCAN_BLOCK_LENGTH);
|
2857 | block = findBlock(scanBytes, EEXEC_SIGNATURE, 0);
|
2858 |
|
2859 | if (block.length === 0) {
|
2860 | break;
|
2861 | }
|
2862 |
|
2863 | stream.pos += block.length;
|
2864 |
|
2865 | if (block.found) {
|
2866 | actualLength = stream.pos - streamStartPos;
|
2867 | break;
|
2868 | }
|
2869 | }
|
2870 |
|
2871 | stream.pos = streamStartPos;
|
2872 |
|
2873 | if (actualLength) {
|
2874 | return {
|
2875 | stream: new _stream.Stream(stream.getBytes(actualLength)),
|
2876 | length: actualLength
|
2877 | };
|
2878 | }
|
2879 |
|
2880 | (0, _util.warn)('Unable to recover "Length1" property in Type1 font -- using as is.');
|
2881 | return {
|
2882 | stream: new _stream.Stream(stream.getBytes(suggestedLength)),
|
2883 | length: suggestedLength
|
2884 | };
|
2885 | }
|
2886 |
|
2887 | function getEexecBlock(stream, suggestedLength) {
|
2888 | var eexecBytes = stream.getBytes();
|
2889 | return {
|
2890 | stream: new _stream.Stream(eexecBytes),
|
2891 | length: eexecBytes.length
|
2892 | };
|
2893 | }
|
2894 |
|
2895 | function Type1Font(name, file, properties) {
|
2896 | var PFB_HEADER_SIZE = 6;
|
2897 | var headerBlockLength = properties.length1;
|
2898 | var eexecBlockLength = properties.length2;
|
2899 | var pfbHeader = file.peekBytes(PFB_HEADER_SIZE);
|
2900 | var pfbHeaderPresent = pfbHeader[0] === 0x80 && pfbHeader[1] === 0x01;
|
2901 |
|
2902 | if (pfbHeaderPresent) {
|
2903 | file.skip(PFB_HEADER_SIZE);
|
2904 | headerBlockLength = pfbHeader[5] << 24 | pfbHeader[4] << 16 | pfbHeader[3] << 8 | pfbHeader[2];
|
2905 | }
|
2906 |
|
2907 | var headerBlock = getHeaderBlock(file, headerBlockLength);
|
2908 | var headerBlockParser = new _type1_parser.Type1Parser(headerBlock.stream, false, SEAC_ANALYSIS_ENABLED);
|
2909 | headerBlockParser.extractFontHeader(properties);
|
2910 |
|
2911 | if (pfbHeaderPresent) {
|
2912 | pfbHeader = file.getBytes(PFB_HEADER_SIZE);
|
2913 | eexecBlockLength = pfbHeader[5] << 24 | pfbHeader[4] << 16 | pfbHeader[3] << 8 | pfbHeader[2];
|
2914 | }
|
2915 |
|
2916 | var eexecBlock = getEexecBlock(file, eexecBlockLength);
|
2917 | var eexecBlockParser = new _type1_parser.Type1Parser(eexecBlock.stream, true, SEAC_ANALYSIS_ENABLED);
|
2918 | var data = eexecBlockParser.extractFontProgram();
|
2919 |
|
2920 | for (var info in data.properties) {
|
2921 | properties[info] = data.properties[info];
|
2922 | }
|
2923 |
|
2924 | var charstrings = data.charstrings;
|
2925 | var type2Charstrings = this.getType2Charstrings(charstrings);
|
2926 | var subrs = this.getType2Subrs(data.subrs);
|
2927 | this.charstrings = charstrings;
|
2928 | this.data = this.wrap(name, type2Charstrings, this.charstrings, subrs, properties);
|
2929 | this.seacs = this.getSeacs(data.charstrings);
|
2930 | }
|
2931 |
|
2932 | Type1Font.prototype = {
|
2933 | get numGlyphs() {
|
2934 | return this.charstrings.length + 1;
|
2935 | },
|
2936 |
|
2937 | getCharset: function Type1Font_getCharset() {
|
2938 | var charset = ['.notdef'];
|
2939 | var charstrings = this.charstrings;
|
2940 |
|
2941 | for (var glyphId = 0; glyphId < charstrings.length; glyphId++) {
|
2942 | charset.push(charstrings[glyphId].glyphName);
|
2943 | }
|
2944 |
|
2945 | return charset;
|
2946 | },
|
2947 | getGlyphMapping: function Type1Font_getGlyphMapping(properties) {
|
2948 | var charstrings = this.charstrings;
|
2949 | var glyphNames = ['.notdef'],
|
2950 | glyphId;
|
2951 |
|
2952 | for (glyphId = 0; glyphId < charstrings.length; glyphId++) {
|
2953 | glyphNames.push(charstrings[glyphId].glyphName);
|
2954 | }
|
2955 |
|
2956 | var encoding = properties.builtInEncoding;
|
2957 |
|
2958 | if (encoding) {
|
2959 | var builtInEncoding = Object.create(null);
|
2960 |
|
2961 | for (var charCode in encoding) {
|
2962 | glyphId = glyphNames.indexOf(encoding[charCode]);
|
2963 |
|
2964 | if (glyphId >= 0) {
|
2965 | builtInEncoding[charCode] = glyphId;
|
2966 | }
|
2967 | }
|
2968 | }
|
2969 |
|
2970 | return type1FontGlyphMapping(properties, builtInEncoding, glyphNames);
|
2971 | },
|
2972 | hasGlyphId: function Type1Font_hasGlyphID(id) {
|
2973 | if (id < 0 || id >= this.numGlyphs) {
|
2974 | return false;
|
2975 | }
|
2976 |
|
2977 | if (id === 0) {
|
2978 | return true;
|
2979 | }
|
2980 |
|
2981 | var glyph = this.charstrings[id - 1];
|
2982 | return glyph.charstring.length > 0;
|
2983 | },
|
2984 | getSeacs: function Type1Font_getSeacs(charstrings) {
|
2985 | var i, ii;
|
2986 | var seacMap = [];
|
2987 |
|
2988 | for (i = 0, ii = charstrings.length; i < ii; i++) {
|
2989 | var charstring = charstrings[i];
|
2990 |
|
2991 | if (charstring.seac) {
|
2992 | seacMap[i + 1] = charstring.seac;
|
2993 | }
|
2994 | }
|
2995 |
|
2996 | return seacMap;
|
2997 | },
|
2998 | getType2Charstrings: function Type1Font_getType2Charstrings(type1Charstrings) {
|
2999 | var type2Charstrings = [];
|
3000 |
|
3001 | for (var i = 0, ii = type1Charstrings.length; i < ii; i++) {
|
3002 | type2Charstrings.push(type1Charstrings[i].charstring);
|
3003 | }
|
3004 |
|
3005 | return type2Charstrings;
|
3006 | },
|
3007 | getType2Subrs: function Type1Font_getType2Subrs(type1Subrs) {
|
3008 | var bias = 0;
|
3009 | var count = type1Subrs.length;
|
3010 |
|
3011 | if (count < 1133) {
|
3012 | bias = 107;
|
3013 | } else if (count < 33769) {
|
3014 | bias = 1131;
|
3015 | } else {
|
3016 | bias = 32768;
|
3017 | }
|
3018 |
|
3019 | var type2Subrs = [];
|
3020 | var i;
|
3021 |
|
3022 | for (i = 0; i < bias; i++) {
|
3023 | type2Subrs.push([0x0B]);
|
3024 | }
|
3025 |
|
3026 | for (i = 0; i < count; i++) {
|
3027 | type2Subrs.push(type1Subrs[i]);
|
3028 | }
|
3029 |
|
3030 | return type2Subrs;
|
3031 | },
|
3032 | wrap: function Type1Font_wrap(name, glyphs, charstrings, subrs, properties) {
|
3033 | var cff = new _cff_parser.CFF();
|
3034 | cff.header = new _cff_parser.CFFHeader(1, 0, 4, 4);
|
3035 | cff.names = [name];
|
3036 | var topDict = new _cff_parser.CFFTopDict();
|
3037 | topDict.setByName('version', 391);
|
3038 | topDict.setByName('Notice', 392);
|
3039 | topDict.setByName('FullName', 393);
|
3040 | topDict.setByName('FamilyName', 394);
|
3041 | topDict.setByName('Weight', 395);
|
3042 | topDict.setByName('Encoding', null);
|
3043 | topDict.setByName('FontMatrix', properties.fontMatrix);
|
3044 | topDict.setByName('FontBBox', properties.bbox);
|
3045 | topDict.setByName('charset', null);
|
3046 | topDict.setByName('CharStrings', null);
|
3047 | topDict.setByName('Private', null);
|
3048 | cff.topDict = topDict;
|
3049 | var strings = new _cff_parser.CFFStrings();
|
3050 | strings.add('Version 0.11');
|
3051 | strings.add('See original notice');
|
3052 | strings.add(name);
|
3053 | strings.add(name);
|
3054 | strings.add('Medium');
|
3055 | cff.strings = strings;
|
3056 | cff.globalSubrIndex = new _cff_parser.CFFIndex();
|
3057 | var count = glyphs.length;
|
3058 | var charsetArray = [0];
|
3059 | var i, ii;
|
3060 |
|
3061 | for (i = 0; i < count; i++) {
|
3062 | var index = _cff_parser.CFFStandardStrings.indexOf(charstrings[i].glyphName);
|
3063 |
|
3064 | if (index === -1) {
|
3065 | index = 0;
|
3066 | }
|
3067 |
|
3068 | charsetArray.push(index >> 8 & 0xff, index & 0xff);
|
3069 | }
|
3070 |
|
3071 | cff.charset = new _cff_parser.CFFCharset(false, 0, [], charsetArray);
|
3072 | var charStringsIndex = new _cff_parser.CFFIndex();
|
3073 | charStringsIndex.add([0x8B, 0x0E]);
|
3074 |
|
3075 | for (i = 0; i < count; i++) {
|
3076 | charStringsIndex.add(glyphs[i]);
|
3077 | }
|
3078 |
|
3079 | cff.charStrings = charStringsIndex;
|
3080 | var privateDict = new _cff_parser.CFFPrivateDict();
|
3081 | privateDict.setByName('Subrs', null);
|
3082 | var fields = ['BlueValues', 'OtherBlues', 'FamilyBlues', 'FamilyOtherBlues', 'StemSnapH', 'StemSnapV', 'BlueShift', 'BlueFuzz', 'BlueScale', 'LanguageGroup', 'ExpansionFactor', 'ForceBold', 'StdHW', 'StdVW'];
|
3083 |
|
3084 | for (i = 0, ii = fields.length; i < ii; i++) {
|
3085 | var field = fields[i];
|
3086 |
|
3087 | if (!(field in properties.privateData)) {
|
3088 | continue;
|
3089 | }
|
3090 |
|
3091 | var value = properties.privateData[field];
|
3092 |
|
3093 | if (Array.isArray(value)) {
|
3094 | for (var j = value.length - 1; j > 0; j--) {
|
3095 | value[j] -= value[j - 1];
|
3096 | }
|
3097 | }
|
3098 |
|
3099 | privateDict.setByName(field, value);
|
3100 | }
|
3101 |
|
3102 | cff.topDict.privateDict = privateDict;
|
3103 | var subrIndex = new _cff_parser.CFFIndex();
|
3104 |
|
3105 | for (i = 0, ii = subrs.length; i < ii; i++) {
|
3106 | subrIndex.add(subrs[i]);
|
3107 | }
|
3108 |
|
3109 | privateDict.subrsIndex = subrIndex;
|
3110 | var compiler = new _cff_parser.CFFCompiler(cff);
|
3111 | return compiler.compile();
|
3112 | }
|
3113 | };
|
3114 | return Type1Font;
|
3115 | }();
|
3116 |
|
3117 | var CFFFont = function CFFFontClosure() {
|
3118 | function CFFFont(file, properties) {
|
3119 | this.properties = properties;
|
3120 | var parser = new _cff_parser.CFFParser(file, properties, SEAC_ANALYSIS_ENABLED);
|
3121 | this.cff = parser.parse();
|
3122 | this.cff.duplicateFirstGlyph();
|
3123 | var compiler = new _cff_parser.CFFCompiler(this.cff);
|
3124 | this.seacs = this.cff.seacs;
|
3125 |
|
3126 | try {
|
3127 | this.data = compiler.compile();
|
3128 | } catch (e) {
|
3129 | (0, _util.warn)('Failed to compile font ' + properties.loadedName);
|
3130 | this.data = file;
|
3131 | }
|
3132 | }
|
3133 |
|
3134 | CFFFont.prototype = {
|
3135 | get numGlyphs() {
|
3136 | return this.cff.charStrings.count;
|
3137 | },
|
3138 |
|
3139 | getCharset: function CFFFont_getCharset() {
|
3140 | return this.cff.charset.charset;
|
3141 | },
|
3142 | getGlyphMapping: function CFFFont_getGlyphMapping() {
|
3143 | var cff = this.cff;
|
3144 | var properties = this.properties;
|
3145 | var charsets = cff.charset.charset;
|
3146 | var charCodeToGlyphId;
|
3147 | var glyphId;
|
3148 |
|
3149 | if (properties.composite) {
|
3150 | charCodeToGlyphId = Object.create(null);
|
3151 |
|
3152 | if (cff.isCIDFont) {
|
3153 | for (glyphId = 0; glyphId < charsets.length; glyphId++) {
|
3154 | var cid = charsets[glyphId];
|
3155 | var charCode = properties.cMap.charCodeOf(cid);
|
3156 | charCodeToGlyphId[charCode] = glyphId;
|
3157 | }
|
3158 | } else {
|
3159 | for (glyphId = 0; glyphId < cff.charStrings.count; glyphId++) {
|
3160 | charCodeToGlyphId[glyphId] = glyphId;
|
3161 | }
|
3162 | }
|
3163 |
|
3164 | return charCodeToGlyphId;
|
3165 | }
|
3166 |
|
3167 | var encoding = cff.encoding ? cff.encoding.encoding : null;
|
3168 | charCodeToGlyphId = type1FontGlyphMapping(properties, encoding, charsets);
|
3169 | return charCodeToGlyphId;
|
3170 | },
|
3171 | hasGlyphId: function CFFFont_hasGlyphID(id) {
|
3172 | return this.cff.hasGlyphId(id);
|
3173 | }
|
3174 | };
|
3175 | return CFFFont;
|
3176 | }(); |
\ | No newline at end of file |