|
|
@ -5050,61 +5050,6 @@ var Type1Font = function Type1Font(name, file, properties) { |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
Type1Font.prototype = { |
|
|
|
Type1Font.prototype = { |
|
|
|
createCFFIndexHeader: function Type1Font_createCFFIndexHeader(objects, |
|
|
|
|
|
|
|
isByte) { |
|
|
|
|
|
|
|
// First 2 bytes contains the number of objects contained into this index
|
|
|
|
|
|
|
|
var count = objects.length; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// If there is no object, just create an array saying that with another
|
|
|
|
|
|
|
|
// offset byte.
|
|
|
|
|
|
|
|
if (count == 0) |
|
|
|
|
|
|
|
return '\x00\x00\x00'; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var data = String.fromCharCode((count >> 8) & 0xFF, count & 0xff); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Next byte 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
|
|
|
|
|
|
|
|
// without thinking of it while coding.
|
|
|
|
|
|
|
|
data += '\x04'; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Add another offset after this one because we need a new offset
|
|
|
|
|
|
|
|
var relativeOffset = 1; |
|
|
|
|
|
|
|
for (var i = 0; i < count + 1; i++) { |
|
|
|
|
|
|
|
data += String.fromCharCode((relativeOffset >>> 24) & 0xFF, |
|
|
|
|
|
|
|
(relativeOffset >> 16) & 0xFF, |
|
|
|
|
|
|
|
(relativeOffset >> 8) & 0xFF, |
|
|
|
|
|
|
|
relativeOffset & 0xFF); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (objects[i]) |
|
|
|
|
|
|
|
relativeOffset += objects[i].length; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (var i = 0; i < count; i++) { |
|
|
|
|
|
|
|
for (var j = 0, jj = objects[i].length; j < jj; j++) |
|
|
|
|
|
|
|
data += isByte ? String.fromCharCode(objects[i][j] & 0xFF) : |
|
|
|
|
|
|
|
objects[i][j]; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return data; |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
encodeNumber: function Type1Font_encodeNumber(value) { |
|
|
|
|
|
|
|
// some of the fonts has ouf-of-range values
|
|
|
|
|
|
|
|
// they are just arithmetic overflows
|
|
|
|
|
|
|
|
// make sanitizer happy
|
|
|
|
|
|
|
|
value |= 0; |
|
|
|
|
|
|
|
if (value >= -32768 && value <= 32767) { |
|
|
|
|
|
|
|
return '\x1c' + |
|
|
|
|
|
|
|
String.fromCharCode((value >> 8) & 0xFF) + |
|
|
|
|
|
|
|
String.fromCharCode(value & 0xFF); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
return '\x1d' + |
|
|
|
|
|
|
|
String.fromCharCode((value >> 24) & 0xFF) + |
|
|
|
|
|
|
|
String.fromCharCode((value >> 16) & 0xFF) + |
|
|
|
|
|
|
|
String.fromCharCode((value >> 8) & 0xFF) + |
|
|
|
|
|
|
|
String.fromCharCode(value & 0xFF); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
getOrderedCharStrings: function Type1Font_getOrderedCharStrings(glyphs, |
|
|
|
getOrderedCharStrings: function Type1Font_getOrderedCharStrings(glyphs, |
|
|
|
properties) { |
|
|
|
properties) { |
|
|
|
var charstrings = []; |
|
|
|
var charstrings = []; |
|
|
@ -5223,9 +5168,9 @@ Type1Font.prototype = { |
|
|
|
if (command > 32000) { |
|
|
|
if (command > 32000) { |
|
|
|
var divisor = charstring[i + 1]; |
|
|
|
var divisor = charstring[i + 1]; |
|
|
|
command /= divisor; |
|
|
|
command /= divisor; |
|
|
|
charstring.splice(i, 3, 28, command >> 8, command & 0xff); |
|
|
|
charstring.splice(i, 3, 28, (command >> 8) & 0xff, command & 0xff); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
charstring.splice(i, 1, 28, command >> 8, command & 0xff); |
|
|
|
charstring.splice(i, 1, 28, (command >> 8) & 0xff, command & 0xff); |
|
|
|
} |
|
|
|
} |
|
|
|
i += 2; |
|
|
|
i += 2; |
|
|
|
} |
|
|
|
} |
|
|
@ -5234,150 +5179,88 @@ Type1Font.prototype = { |
|
|
|
}, |
|
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
wrap: function Type1Font_wrap(name, glyphs, charstrings, subrs, properties) { |
|
|
|
wrap: function Type1Font_wrap(name, glyphs, charstrings, subrs, properties) { |
|
|
|
var comp = new CFFCompiler(); |
|
|
|
var cff = new CFF(); |
|
|
|
// TODO: remove this function after refactoring wrap to use the CFFCompiler.
|
|
|
|
cff.header = new CFFHeader(1, 0, 4, 4); |
|
|
|
function encodeNumber(num) { |
|
|
|
|
|
|
|
var val = comp.encodeNumber(num); |
|
|
|
cff.names = [name]; |
|
|
|
var ret = ''; |
|
|
|
|
|
|
|
for (var i = 0; i < val.length; i++) { |
|
|
|
var topDict = new CFFTopDict(); |
|
|
|
ret += String.fromCharCode(val[i]); |
|
|
|
topDict.setByName('version', 0); |
|
|
|
} |
|
|
|
topDict.setByName('Notice', 1); |
|
|
|
return ret; |
|
|
|
topDict.setByName('FullName', 2); |
|
|
|
|
|
|
|
topDict.setByName('FamilyName', 3); |
|
|
|
|
|
|
|
topDict.setByName('Weight', 4); |
|
|
|
|
|
|
|
topDict.setByName('Encoding', null); // placeholder
|
|
|
|
|
|
|
|
topDict.setByName('FontBBox', properties.bbox); |
|
|
|
|
|
|
|
topDict.setByName('charset', null); // placeholder
|
|
|
|
|
|
|
|
topDict.setByName('CharStrings', null); // placeholder
|
|
|
|
|
|
|
|
topDict.setByName('Private', null); // placeholder
|
|
|
|
|
|
|
|
cff.topDict = topDict; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var strings = new CFFStrings(); |
|
|
|
|
|
|
|
strings.add('Version 0.11'); // Version
|
|
|
|
|
|
|
|
strings.add('See original notice'); // Notice
|
|
|
|
|
|
|
|
strings.add(name); // FullName
|
|
|
|
|
|
|
|
strings.add(name); // FamilyName
|
|
|
|
|
|
|
|
strings.add('Medium'); // Weight
|
|
|
|
|
|
|
|
cff.strings = strings; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cff.globalSubrIndex = new CFFIndex(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var count = glyphs.length; |
|
|
|
|
|
|
|
var charsetArray = [0]; |
|
|
|
|
|
|
|
for (var i = 0; i < count; i++) { |
|
|
|
|
|
|
|
var index = CFFStandardStrings.indexOf(charstrings[i].glyph); |
|
|
|
|
|
|
|
// Some characters like asterikmath && circlecopyrt are
|
|
|
|
|
|
|
|
// missing from the original strings, for the moment let's
|
|
|
|
|
|
|
|
// map them to .notdef and see later if it cause any
|
|
|
|
|
|
|
|
// problems
|
|
|
|
|
|
|
|
if (index == -1) |
|
|
|
|
|
|
|
index = 0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
charsetArray.push((index >> 8) & 0xff, index & 0xff); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
cff.charset = new CFFCharset(false, 0, [], charsetArray); |
|
|
|
|
|
|
|
|
|
|
|
var fields = { |
|
|
|
var charStringsIndex = new CFFIndex(); |
|
|
|
// major version, minor version, header size, offset size
|
|
|
|
charStringsIndex.add([0x8B, 0x0E]); // .notdef
|
|
|
|
'header': '\x01\x00\x04\x04', |
|
|
|
for (var i = 0; i < count; i++) { |
|
|
|
|
|
|
|
charStringsIndex.add(glyphs[i]); |
|
|
|
'names': this.createCFFIndexHeader([name]), |
|
|
|
} |
|
|
|
|
|
|
|
cff.charStrings = charStringsIndex; |
|
|
|
'topDict': (function topDict(self) { |
|
|
|
|
|
|
|
return function cffWrapTopDict() { |
|
|
|
var privateDict = new CFFPrivateDict(); |
|
|
|
var header = '\x00\x01\x01\x01'; |
|
|
|
privateDict.setByName('Subrs', null); // placeholder
|
|
|
|
var dict = |
|
|
|
var fields = [ |
|
|
|
'\xf8\x1b\x00' + // version
|
|
|
|
// TODO: missing StdHW, StdVW, ForceBold
|
|
|
|
'\xf8\x1c\x01' + // Notice
|
|
|
|
'BlueValues', |
|
|
|
'\xf8\x1d\x02' + // FullName
|
|
|
|
'OtherBlues', |
|
|
|
'\xf8\x1e\x03' + // FamilyName
|
|
|
|
'FamilyBlues', |
|
|
|
'\xf8\x1f\x04' + // Weight
|
|
|
|
'FamilyOtherBlues', |
|
|
|
'\x1c\x00\x00\x10'; // Encoding
|
|
|
|
'StemSnapH', |
|
|
|
|
|
|
|
'StemSnapV', |
|
|
|
var boundingBox = properties.bbox; |
|
|
|
'BlueShift', |
|
|
|
for (var i = 0, ii = boundingBox.length; i < ii; i++) |
|
|
|
'BlueFuzz', |
|
|
|
dict += encodeNumber(boundingBox[i]); |
|
|
|
'BlueScale', |
|
|
|
dict += '\x05'; // FontBBox;
|
|
|
|
'LanguageGroup', |
|
|
|
|
|
|
|
'ExpansionFactor' |
|
|
|
var offset = fields.header.length + |
|
|
|
]; |
|
|
|
fields.names.length + |
|
|
|
for (var i = 0, ii = fields.length; i < ii; i++) { |
|
|
|
(header.length + 1) + |
|
|
|
var field = fields[i]; |
|
|
|
(dict.length + (4 + 4)) + |
|
|
|
if (!properties.privateData.hasOwnProperty(field)) |
|
|
|
fields.strings.length + |
|
|
|
continue; |
|
|
|
fields.globalSubrs.length; |
|
|
|
privateDict.setByName(field, properties.privateData[field]); |
|
|
|
|
|
|
|
} |
|
|
|
// If the offset if over 32767, encodeNumber is going to return
|
|
|
|
cff.topDict.privateDict = privateDict; |
|
|
|
// 5 bytes to encode the position instead of 3.
|
|
|
|
|
|
|
|
if ((offset + fields.charstrings.length) > 32767) { |
|
|
|
|
|
|
|
offset += 9; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
offset += 7; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
dict += self.encodeNumber(offset) + '\x0f'; // Charset
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
offset = offset + (glyphs.length * 2) + 1; |
|
|
|
|
|
|
|
dict += self.encodeNumber(offset) + '\x11'; // Charstrings
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
offset = offset + fields.charstrings.length; |
|
|
|
|
|
|
|
dict += self.encodeNumber(fields.privateData.length); |
|
|
|
|
|
|
|
dict += self.encodeNumber(offset) + '\x12'; // Private
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return header + String.fromCharCode(dict.length + 1) + dict; |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
})(this), |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
'strings': (function strings(self) { |
|
|
|
|
|
|
|
var strings = [ |
|
|
|
|
|
|
|
'Version 0.11', // Version
|
|
|
|
|
|
|
|
'See original notice', // Notice
|
|
|
|
|
|
|
|
name, // FullName
|
|
|
|
|
|
|
|
name, // FamilyName
|
|
|
|
|
|
|
|
'Medium' // Weight
|
|
|
|
|
|
|
|
]; |
|
|
|
|
|
|
|
return self.createCFFIndexHeader(strings); |
|
|
|
|
|
|
|
})(this), |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
'globalSubrs': this.createCFFIndexHeader([]), |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
'charset': (function charset(self) { |
|
|
|
|
|
|
|
var charsetString = '\x00'; // Encoding
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var count = glyphs.length; |
|
|
|
|
|
|
|
for (var i = 0; i < count; i++) { |
|
|
|
|
|
|
|
var index = CFFStandardStrings.indexOf(charstrings[i].glyph); |
|
|
|
|
|
|
|
// Some characters like asterikmath && circlecopyrt are
|
|
|
|
|
|
|
|
// missing from the original strings, for the moment let's
|
|
|
|
|
|
|
|
// map them to .notdef and see later if it cause any
|
|
|
|
|
|
|
|
// problems
|
|
|
|
|
|
|
|
if (index == -1) |
|
|
|
|
|
|
|
index = 0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
charsetString += String.fromCharCode(index >> 8, index & 0xff); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return charsetString; |
|
|
|
|
|
|
|
})(this), |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
'charstrings': this.createCFFIndexHeader([[0x8B, 0x0E]].concat(glyphs), |
|
|
|
|
|
|
|
true), |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
'privateData': (function cffWrapPrivate(self) { |
|
|
|
|
|
|
|
var data = |
|
|
|
|
|
|
|
'\x8b\x14' + // defaultWidth
|
|
|
|
|
|
|
|
'\x8b\x15'; // nominalWidth
|
|
|
|
|
|
|
|
var fieldMap = { |
|
|
|
|
|
|
|
BlueValues: '\x06', |
|
|
|
|
|
|
|
OtherBlues: '\x07', |
|
|
|
|
|
|
|
FamilyBlues: '\x08', |
|
|
|
|
|
|
|
FamilyOtherBlues: '\x09', |
|
|
|
|
|
|
|
StemSnapH: '\x0c\x0c', |
|
|
|
|
|
|
|
StemSnapV: '\x0c\x0d', |
|
|
|
|
|
|
|
BlueShift: '\x0c\x0a', |
|
|
|
|
|
|
|
BlueFuzz: '\x0c\x0b', |
|
|
|
|
|
|
|
BlueScale: '\x0c\x09', |
|
|
|
|
|
|
|
LanguageGroup: '\x0c\x11', |
|
|
|
|
|
|
|
ExpansionFactor: '\x0c\x12' |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
for (var field in fieldMap) { |
|
|
|
|
|
|
|
if (!properties.privateData.hasOwnProperty(field)) |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
var value = properties.privateData[field]; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (isArray(value)) { |
|
|
|
|
|
|
|
for (var i = 0, ii = value.length; i < ii; i++) |
|
|
|
|
|
|
|
data += encodeNumber(value[i]); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
data += encodeNumber(value); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
data += fieldMap[field]; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
data += self.encodeNumber(data.length + 4) + '\x13'; // Subrs offset
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return data; |
|
|
|
|
|
|
|
})(this), |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
'localSubrs': this.createCFFIndexHeader(subrs, true) |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
fields.topDict = fields.topDict(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var cff = []; |
|
|
|
var subrIndex = new CFFIndex(); |
|
|
|
for (var index in fields) { |
|
|
|
for (var i = 0, ii = subrs.length; i < ii; i++) { |
|
|
|
var field = fields[index]; |
|
|
|
subrIndex.add(subrs[i]); |
|
|
|
for (var i = 0, ii = field.length; i < ii; i++) |
|
|
|
|
|
|
|
cff.push(field.charCodeAt(i)); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
privateDict.subrsIndex = subrIndex; |
|
|
|
|
|
|
|
|
|
|
|
return cff; |
|
|
|
var compiler = new CFFCompiler(cff); |
|
|
|
|
|
|
|
return compiler.compile(); |
|
|
|
} |
|
|
|
} |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
@ -6187,6 +6070,12 @@ var CFFDict = (function CFFDictClosure() { |
|
|
|
this.values[key] = value; |
|
|
|
this.values[key] = value; |
|
|
|
return true; |
|
|
|
return true; |
|
|
|
}, |
|
|
|
}, |
|
|
|
|
|
|
|
setByName: function CFFDict_setByName(name, value) { |
|
|
|
|
|
|
|
if (!(name in this.nameToKeyMap)) { |
|
|
|
|
|
|
|
error('Invalid dictionary name "' + name + '"'); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
this.values[this.nameToKeyMap[name]] = value; |
|
|
|
|
|
|
|
}, |
|
|
|
hasName: function CFFDict_hasName(name) { |
|
|
|
hasName: function CFFDict_hasName(name) { |
|
|
|
return this.nameToKeyMap[name] in this.values; |
|
|
|
return this.nameToKeyMap[name] in this.values; |
|
|
|
}, |
|
|
|
}, |
|
|
|