Browse Source

Replace variables named 'char'=>'character', 'byte'=>'octet' and field '.private'=>'.privateData'. This allows pdf.js to compile with Google's Closure Compiler.

gigaherz 13 years ago
parent
commit
c6d7e654ee
  1. 10
      src/canvas.js
  2. 12
      src/evaluator.js
  3. 86
      src/fonts.js
  4. 4
      src/image.js
  5. 4
      src/obj.js
  6. 4
      src/parser.js
  7. 6
      src/stream.js
  8. 8
      src/utils/fonts_utils.js

10
src/canvas.js

@ -752,7 +752,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
continue; continue;
} }
var char = glyph.fontChar; var character = glyph.fontChar;
var charWidth = glyph.width * fontSize * 0.001 + var charWidth = glyph.width * fontSize * 0.001 +
Util.sign(current.fontMatrix[0]) * charSpacing; Util.sign(current.fontMatrix[0]) * charSpacing;
@ -762,16 +762,16 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
default: // other unsupported rendering modes default: // other unsupported rendering modes
case TextRenderingMode.FILL: case TextRenderingMode.FILL:
case TextRenderingMode.FILL_ADD_TO_PATH: case TextRenderingMode.FILL_ADD_TO_PATH:
ctx.fillText(char, scaledX, 0); ctx.fillText(character, scaledX, 0);
break; break;
case TextRenderingMode.STROKE: case TextRenderingMode.STROKE:
case TextRenderingMode.STROKE_ADD_TO_PATH: case TextRenderingMode.STROKE_ADD_TO_PATH:
ctx.strokeText(char, scaledX, 0); ctx.strokeText(character, scaledX, 0);
break; break;
case TextRenderingMode.FILL_STROKE: case TextRenderingMode.FILL_STROKE:
case TextRenderingMode.FILL_STROKE_ADD_TO_PATH: case TextRenderingMode.FILL_STROKE_ADD_TO_PATH:
ctx.fillText(char, scaledX, 0); ctx.fillText(character, scaledX, 0);
ctx.strokeText(char, scaledX, 0); ctx.strokeText(character, scaledX, 0);
break; break;
case TextRenderingMode.INVISIBLE: case TextRenderingMode.INVISIBLE:
break; break;

12
src/evaluator.js

@ -536,9 +536,9 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
var cmap = cmapObj.getBytes(cmapObj.length); var cmap = cmapObj.getBytes(cmapObj.length);
for (var i = 0, ii = cmap.length; i < ii; i++) { for (var i = 0, ii = cmap.length; i < ii; i++) {
var byte = cmap[i]; var octet = cmap[i];
if (byte == 0x20 || byte == 0x0D || byte == 0x0A || if (octet == 0x20 || octet == 0x0D || octet == 0x0A ||
byte == 0x3C || byte == 0x5B || byte == 0x5D) { octet == 0x3C || octet == 0x5B || octet == 0x5D) {
switch (token) { switch (token) {
case 'usecmap': case 'usecmap':
error('usecmap is not implemented'); error('usecmap is not implemented');
@ -595,7 +595,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
tokens.push(token); tokens.push(token);
token = ''; token = '';
} }
switch (byte) { switch (octet) {
case 0x5B: case 0x5B:
// begin list parsing // begin list parsing
tokens.push(beginArrayToken); tokens.push(beginArrayToken);
@ -609,7 +609,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
tokens.push(items); tokens.push(items);
break; break;
} }
} else if (byte == 0x3E) { } else if (octet == 0x3E) {
if (token.length) { if (token.length) {
if (token.length <= 4) { if (token.length <= 4) {
// parsing hex number // parsing hex number
@ -635,7 +635,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
} }
} }
} else { } else {
token += String.fromCharCode(byte); token += String.fromCharCode(octet);
} }
} }
} }

86
src/fonts.js

@ -390,7 +390,7 @@ var symbolsFonts = {
'Dingbats': true, 'Symbol': true, 'ZapfDingbats': true 'Dingbats': true, 'Symbol': true, 'ZapfDingbats': true
}; };
// Some characters, e.g. copyrightserif, mapped to the private use area and // Some characters, e.g. copyrightserif, mapped to the privateData use area and
// might not be displayed using standard fonts. Mapping/hacking well-known chars // might not be displayed using standard fonts. Mapping/hacking well-known chars
// to the similar equivalents in the normal characters range. // to the similar equivalents in the normal characters range.
function mapPrivateUseChars(code) { function mapPrivateUseChars(code) {
@ -1216,7 +1216,7 @@ var Font = (function FontClosure() {
'Unknown' // 9.Designer 'Unknown' // 9.Designer
]; ];
// Mac want 1-byte per character strings while Windows want // Mac want 1-octet per character strings while Windows want
// 2-bytes per character, so duplicate the names table // 2-bytes per character, so duplicate the names table
var stringsUnicode = []; var stringsUnicode = [];
for (var i = 0, ii = strings.length; i < ii; i++) { for (var i = 0, ii = strings.length; i < ii; i++) {
@ -1970,7 +1970,7 @@ var Font = (function FontClosure() {
minUnicode = Math.min(minUnicode, unicode); minUnicode = Math.min(minUnicode, unicode);
maxUnicode = Math.max(maxUnicode, unicode); maxUnicode = Math.max(maxUnicode, unicode);
} }
// high byte must be the same for min and max unicodes // high octet must be the same for min and max unicodes
if ((maxUnicode & 0xFF00) != (minUnicode & 0xFF00)) if ((maxUnicode & 0xFF00) != (minUnicode & 0xFF00))
this.isSymbolicFont = false; this.isSymbolicFont = false;
} }
@ -1986,7 +1986,7 @@ var Font = (function FontClosure() {
if (hasShortCmap && this.hasEncoding && !this.isSymbolicFont) { if (hasShortCmap && this.hasEncoding && !this.isSymbolicFont) {
// Re-encode short map encoding to unicode -- that simplifies the // Re-encode short map encoding to unicode -- that simplifies the
// resolution of MacRoman encoded glyphs logic for TrueType fonts: // resolution of MacRoman encoded glyphs logic for TrueType fonts:
// copying all characters to private use area, all mapping all known // copying all characters to privateData use area, all mapping all known
// glyphs to the unicodes. The glyphs and ids arrays will grow. // glyphs to the unicodes. The glyphs and ids arrays will grow.
var usedUnicodes = []; var usedUnicodes = [];
for (var i = 0, ii = glyphs.length; i < ii; i++) { for (var i = 0, ii = glyphs.length; i < ii; i++) {
@ -2114,7 +2114,7 @@ var Font = (function FontClosure() {
var tableData = table.data; var tableData = table.data;
ttf.file += arrayToString(tableData); ttf.file += arrayToString(tableData);
// 4-byte aligned data // 4-octet aligned data
while (ttf.file.length & 3) while (ttf.file.length & 3)
ttf.file += String.fromCharCode(0); ttf.file += String.fromCharCode(0);
} }
@ -2504,12 +2504,12 @@ var Font = (function FontClosure() {
glyphs = []; glyphs = [];
if (this.composite) { if (this.composite) {
// composite fonts have multi-byte strings convert the string from // composite fonts have multi-octet strings convert the string from
// single-byte to multi-byte // single-octet to multi-octet
// XXX assuming CIDFonts are two-byte - later need to extract the // XXX assuming CIDFonts are two-octet - later need to extract the
// correct byte encoding according to the PDF spec // correct octet encoding according to the PDF spec
var length = chars.length - 1; // looping over two bytes at a time so var length = chars.length - 1; // looping over two bytes at a time so
// loop should never end on the last byte // loop should never end on the last octet
for (var i = 0; i < length; i++) { for (var i = 0; i < length; i++) {
var charcode = int16([chars.charCodeAt(i++), chars.charCodeAt(i)]); var charcode = int16([chars.charCodeAt(i++), chars.charCodeAt(i)]);
var glyph = this.charToGlyph(charcode); var glyph = this.charToGlyph(charcode);
@ -2568,37 +2568,37 @@ var Type1Parser = function type1Parser() {
/* /*
* CharStrings are encoded following the the CharString Encoding sequence * CharStrings are encoded following the the CharString Encoding sequence
* describe in Chapter 6 of the "Adobe Type1 Font Format" specification. * describe in Chapter 6 of the "Adobe Type1 Font Format" specification.
* The value in a byte indicates a command, a number, or subsequent bytes * The value in a octet indicates a command, a number, or subsequent bytes
* that are to be interpreted in a special way. * that are to be interpreted in a special way.
* *
* CharString Number Encoding: * CharString Number Encoding:
* A CharString byte containing the values from 32 through 255 inclusive * A CharString octet containing the values from 32 through 255 inclusive
* indicate an integer. These values are decoded in four ranges. * indicate an integer. These values are decoded in four ranges.
* *
* 1. A CharString byte containing a value, v, between 32 and 246 inclusive, * 1. A CharString octet containing a value, v, between 32 and 246 inclusive,
* indicate the integer v - 139. Thus, the integer values from -107 through * indicate the integer v - 139. Thus, the integer values from -107 through
* 107 inclusive may be encoded in single byte. * 107 inclusive may be encoded in single octet.
* *
* 2. A CharString byte containing a value, v, between 247 and 250 inclusive, * 2. A CharString octet containing a value, v, between 247 and 250 inclusive,
* indicates an integer involving the next byte, w, according to the formula: * indicates an integer involving the next octet, w, according to the formula:
* [(v - 247) x 256] + w + 108 * [(v - 247) x 256] + w + 108
* *
* 3. A CharString byte containing a value, v, between 251 and 254 inclusive, * 3. A CharString octet containing a value, v, between 251 and 254 inclusive,
* indicates an integer involving the next byte, w, according to the formula: * indicates an integer involving the next octet, w, according to the formula:
* -[(v - 251) * 256] - w - 108 * -[(v - 251) * 256] - w - 108
* *
* 4. A CharString containing the value 255 indicates that the next 4 bytes * 4. A CharString containing the value 255 indicates that the next 4 bytes
* are a two complement signed integer. The first of these bytes contains the * are a two complement signed integer. The first of these bytes contains the
* highest order bits, the second byte contains the next higher order bits * highest order bits, the second octet contains the next higher order bits
* and the fourth byte contain the lowest order bits. * and the fourth octet contain the lowest order bits.
* *
* *
* CharString Command Encoding: * CharString Command Encoding:
* CharStrings commands are encoded in 1 or 2 bytes. * CharStrings commands are encoded in 1 or 2 bytes.
* *
* Single byte commands are encoded in 1 byte that contains a value between * Single octet commands are encoded in 1 octet that contains a value between
* 0 and 31 inclusive. * 0 and 31 inclusive.
* If a command byte contains the value 12, then the value in the next byte * If a command octet contains the value 12, then the value in the next octet
* indicates a command. This "escape" mechanism allows many extra commands * indicates a command. This "escape" mechanism allows many extra commands
* to be encoded and this encoding technique helps to minimize the length of * to be encoded and this encoding technique helps to minimize the length of
* the charStrings. * the charStrings.
@ -2861,7 +2861,7 @@ var Type1Parser = function type1Parser() {
subrs: [], subrs: [],
charstrings: [], charstrings: [],
properties: { properties: {
'private': { 'privateData': {
'lenIV': 4 'lenIV': 4
} }
} }
@ -2890,7 +2890,7 @@ var Type1Parser = function type1Parser() {
(token == 'RD' || token == '-|')) { (token == 'RD' || token == '-|')) {
i++; i++;
var data = eexec.slice(i, i + length); var data = eexec.slice(i, i + length);
var lenIV = program.properties.private['lenIV']; var lenIV = program.properties.privateData['lenIV'];
var encoded = decrypt(data, kCharStringsEncryptionKey, lenIV); var encoded = decrypt(data, kCharStringsEncryptionKey, lenIV);
var str = decodeCharString(encoded); var str = decodeCharString(encoded);
@ -2930,7 +2930,7 @@ var Type1Parser = function type1Parser() {
var length = parseInt(getToken(), 10); var length = parseInt(getToken(), 10);
getToken(); // read in 'RD' getToken(); // read in 'RD'
var data = eexec.slice(i + 1, i + 1 + length); var data = eexec.slice(i + 1, i + 1 + length);
var lenIV = program.properties.private['lenIV']; var lenIV = program.properties.privateData['lenIV'];
var encoded = decrypt(data, kCharStringsEncryptionKey, lenIV); var encoded = decrypt(data, kCharStringsEncryptionKey, lenIV);
var str = decodeCharString(encoded); var str = decodeCharString(encoded);
i = i + 1 + length; i = i + 1 + length;
@ -2946,12 +2946,12 @@ var Type1Parser = function type1Parser() {
case '/FamilyOtherBlues': case '/FamilyOtherBlues':
case '/StemSnapH': case '/StemSnapH':
case '/StemSnapV': case '/StemSnapV':
program.properties.private[token.substring(1)] = program.properties.privateData[token.substring(1)] =
readNumberArray(eexecStr, i + 1); readNumberArray(eexecStr, i + 1);
break; break;
case '/StdHW': case '/StdHW':
case '/StdVW': case '/StdVW':
program.properties.private[token.substring(1)] = program.properties.privateData[token.substring(1)] =
readNumberArray(eexecStr, i + 2)[0]; readNumberArray(eexecStr, i + 2)[0];
break; break;
case '/BlueShift': case '/BlueShift':
@ -2960,7 +2960,7 @@ var Type1Parser = function type1Parser() {
case '/BlueScale': case '/BlueScale':
case '/LanguageGroup': case '/LanguageGroup':
case '/ExpansionFactor': case '/ExpansionFactor':
program.properties.private[token.substring(1)] = program.properties.privateData[token.substring(1)] =
readNumber(eexecStr, i + 1); readNumber(eexecStr, i + 1);
break; break;
} }
@ -2984,14 +2984,14 @@ var Type1Parser = function type1Parser() {
var count = headerString.length; var count = headerString.length;
for (var i = 0; i < count; i++) { for (var i = 0; i < count; i++) {
var getToken = function getToken() { var getToken = function getToken() {
var char = headerString[i]; var character = headerString[i];
while (i < count && (isSeparator(char) || char == '/')) while (i < count && (isSeparator(character) || character == '/'))
char = headerString[++i]; character = headerString[++i];
var token = ''; var token = '';
while (i < count && !(isSeparator(char) || char == '/')) { while (i < count && !(isSeparator(character) || character == '/')) {
token += char; token += character;
char = headerString[++i]; character = headerString[++i];
} }
return token; return token;
@ -3148,13 +3148,13 @@ Type1Font.prototype = {
var count = objects.length; var count = objects.length;
// If there is no object, just create an array saying that with another // If there is no object, just create an array saying that with another
// offset byte. // offset octet.
if (count == 0) if (count == 0)
return '\x00\x00\x00'; return '\x00\x00\x00';
var data = String.fromCharCode((count >> 8) & 0xFF, count & 0xff); var data = String.fromCharCode((count >> 8) & 0xFF, count & 0xff);
// Next byte contains the offset size use to reference object in the file // Next octet contains the offset size use to reference object in the file
// Actually we're using 0x04 to be sure to be able to store everything // Actually we're using 0x04 to be sure to be able to store everything
// without thinking of it while coding. // without thinking of it while coding.
data += '\x04'; data += '\x04';
@ -3357,7 +3357,7 @@ Type1Font.prototype = {
dict += self.encodeNumber(offset) + '\x11'; // Charstrings dict += self.encodeNumber(offset) + '\x11'; // Charstrings
offset = offset + fields.charstrings.length; offset = offset + fields.charstrings.length;
dict += self.encodeNumber(fields.private.length); dict += self.encodeNumber(fields.privateData.length);
dict += self.encodeNumber(offset) + '\x12'; // Private dict += self.encodeNumber(offset) + '\x12'; // Private
return header + String.fromCharCode(dict.length + 1) + dict; return header + String.fromCharCode(dict.length + 1) + dict;
@ -3398,7 +3398,7 @@ Type1Font.prototype = {
'charstrings': this.createCFFIndexHeader([[0x8B, 0x0E]].concat(glyphs), 'charstrings': this.createCFFIndexHeader([[0x8B, 0x0E]].concat(glyphs),
true), true),
'private': (function cffWrapPrivate(self) { 'privateData': (function cffWrapPrivate(self) {
var data = var data =
'\x8b\x14' + // defaultWidth '\x8b\x14' + // defaultWidth
'\x8b\x15'; // nominalWidth '\x8b\x15'; // nominalWidth
@ -3416,9 +3416,9 @@ Type1Font.prototype = {
ExpansionFactor: '\x0c\x18' ExpansionFactor: '\x0c\x18'
}; };
for (var field in fieldMap) { for (var field in fieldMap) {
if (!properties.private.hasOwnProperty(field)) if (!properties.privateData.hasOwnProperty(field))
continue; continue;
var value = properties.private[field]; var value = properties.privateData[field];
if (isArray(value)) { if (isArray(value)) {
data += self.encodeNumber(value[0]); data += self.encodeNumber(value[0]);
@ -3800,7 +3800,7 @@ var CFFParser = (function CFFParserClosure() {
return charStrings; return charStrings;
}, },
parsePrivateDict: function parsePrivateDict(parentDict) { parsePrivateDict: function parsePrivateDict(parentDict) {
// no private dict, do nothing // no privateData dict, do nothing
if (!parentDict.hasName('Private')) if (!parentDict.hasName('Private'))
return; return;
var privateOffset = parentDict.getByName('Private'); var privateOffset = parentDict.getByName('Private');
@ -3824,7 +3824,7 @@ var CFFParser = (function CFFParserClosure() {
parentDict.strings); parentDict.strings);
parentDict.privateDict = privateDict; parentDict.privateDict = privateDict;
// Parse the Subrs index also since it's relative to the private dict. // Parse the Subrs index also since it's relative to the privateData dict.
if (!privateDict.getByName('Subrs')) if (!privateDict.getByName('Subrs'))
return; return;
var subrsOffset = privateDict.getByName('Subrs'); var subrsOffset = privateDict.getByName('Subrs');
@ -4611,7 +4611,7 @@ var CFFCompiler = (function CFFCompilerClosure() {
else else
offsetSize = 4; offsetSize = 4;
// Next byte contains the offset size use to reference object in the file // Next octet contains the offset size use to reference object in the file
data.push(offsetSize); data.push(offsetSize);
// Add another offset after this one because we need a new offset // Add another offset after this one because we need a new offset

4
src/image.js

@ -314,7 +314,7 @@ var PDFImage = (function PDFImageClosure() {
var originalHeight = this.height; var originalHeight = this.height;
var bpc = this.bpc; var bpc = this.bpc;
// rows start at byte boundary; // rows start at octet boundary;
var rowBytes = (originalWidth * numComps * bpc + 7) >> 3; var rowBytes = (originalWidth * numComps * bpc + 7) >> 3;
var imgArray = this.getImageBytes(originalHeight * rowBytes); var imgArray = this.getImageBytes(originalHeight * rowBytes);
@ -344,7 +344,7 @@ var PDFImage = (function PDFImageClosure() {
var height = this.height; var height = this.height;
var bpc = this.bpc; var bpc = this.bpc;
// rows start at byte boundary; // rows start at octet boundary;
var rowBytes = (width * numComps * bpc + 7) >> 3; var rowBytes = (width * numComps * bpc + 7) >> 3;
var imgArray = this.getImageBytes(height * rowBytes); var imgArray = this.getImageBytes(height * rowBytes);

4
src/obj.js

@ -438,7 +438,7 @@ var XRef = (function XRefClosure() {
function skipUntil(data, offset, what) { function skipUntil(data, offset, what) {
var length = what.length, dataLength = data.length; var length = what.length, dataLength = data.length;
var skipped = 0; var skipped = 0;
// finding byte sequence // finding octet sequence
while (offset < dataLength) { while (offset < dataLength) {
var i = 0; var i = 0;
while (i < length && data[offset + i] == what[i]) while (i < length && data[offset + i] == what[i])
@ -494,7 +494,7 @@ var XRef = (function XRefClosure() {
var content = buffer.subarray(position, position + contentLength); var content = buffer.subarray(position, position + contentLength);
// checking XRef stream suspect // checking XRef stream suspect
// (it shall have '/XRef' and next char is not a letter) // (it shall have '/XRef' and next character is not a letter)
var xrefTagOffset = skipUntil(content, 0, xrefBytes); var xrefTagOffset = skipUntil(content, 0, xrefBytes);
if (xrefTagOffset < contentLength && if (xrefTagOffset < contentLength &&
content[xrefTagOffset + 5] < 64) { content[xrefTagOffset + 5] < 64) {

4
src/parser.js

@ -27,7 +27,7 @@ var Parser = (function ParserClosure() {
if (isCmd(this.buf2, 'ID')) { if (isCmd(this.buf2, 'ID')) {
this.buf1 = this.buf2; this.buf1 = this.buf2;
this.buf2 = null; this.buf2 = null;
// skip byte after ID // skip octet after ID
this.lexer.skip(); this.lexer.skip();
} else { } else {
this.buf1 = this.buf2; this.buf1 = this.buf2;
@ -424,7 +424,7 @@ var Lexer = (function LexerClosure() {
stream.skip(); stream.skip();
var x2 = toHexDigit(stream.getChar()); var x2 = toHexDigit(stream.getChar());
if (x2 == -1) if (x2 == -1)
error('Illegal digit in hex char in name: ' + x2); error('Illegal digit in hex character in name: ' + x2);
str += String.fromCharCode((x << 4) | x2); str += String.fromCharCode((x << 4) | x2);
} else { } else {
str += '#'; str += '#';

6
src/stream.js

@ -1162,10 +1162,10 @@ var RunLengthStream = (function RunLengthStreamClosure() {
RunLengthStream.prototype = Object.create(DecodeStream.prototype); RunLengthStream.prototype = Object.create(DecodeStream.prototype);
RunLengthStream.prototype.readBlock = function runLengthStreamReadBlock() { RunLengthStream.prototype.readBlock = function runLengthStreamReadBlock() {
// The repeatHeader has following format. The first byte defines type of run // The repeatHeader has following format. The first octet defines type of run
// and amount of bytes to repeat/copy: n = 0 through 127 - copy next n bytes // and amount of bytes to repeat/copy: n = 0 through 127 - copy next n bytes
// (in addition to the second byte from the header), n = 129 through 255 - // (in addition to the second octet from the header), n = 129 through 255 -
// duplicate the second byte from the header (257 - n) times, n = 128 - end. // duplicate the second octet from the header (257 - n) times, n = 128 - end.
var repeatHeader = this.str.getBytes(2); var repeatHeader = this.str.getBytes(2);
if (!repeatHeader || repeatHeader.length < 2 || repeatHeader[0] == 128) { if (!repeatHeader || repeatHeader.length < 2 || repeatHeader[0] == 128) {
this.eof = true; this.eof = true;

8
src/utils/fonts_utils.js

@ -122,9 +122,9 @@ function readFontDictData(aString, aMap) {
token = ''; token = '';
var parsed = false; var parsed = false;
while (!parsed) { while (!parsed) {
var byte = aString[i++]; var octet = aString[i++];
var nibbles = [parseInt(byte / 16, 10), parseInt(byte % 16, 10)]; var nibbles = [parseInt(octet / 16, 10), parseInt(octet % 16, 10)];
for (var j = 0; j < nibbles.length; j++) { for (var j = 0; j < nibbles.length; j++) {
var nibble = nibbles[j]; var nibble = nibbles[j];
switch (nibble) { switch (nibble) {
@ -175,7 +175,7 @@ function readFontDictData(aString, aMap) {
* In CFF an INDEX is a structure with the following format: * In CFF an INDEX is a structure with the following format:
* { * {
* count: 2 bytes (Number of objects stored in INDEX), * count: 2 bytes (Number of objects stored in INDEX),
* offsize: 1 byte (Offset array element size), * offsize: 1 octet (Offset array element size),
* offset: [count + 1] bytes (Offsets array), * offset: [count + 1] bytes (Offsets array),
* data: - (Objects data) * data: - (Objects data)
* } * }
@ -336,7 +336,7 @@ var Type2Parser = function type2Parser(aFilePath) {
var privateDict = []; var privateDict = [];
for (var i = 0; i < priv.size; i++) for (var i = 0; i < priv.size; i++)
privateDict.push(aStream.getByte()); privateDict.push(aStream.getByte());
dump('private:' + privateDict); dump('privateData:' + privateDict);
parseAsToken(privateDict, CFFDictPrivateDataMap); parseAsToken(privateDict, CFFDictPrivateDataMap);
for (var p in font.map) for (var p in font.map)

Loading…
Cancel
Save