|
|
@ -1631,133 +1631,104 @@ CFF.prototype = { |
|
|
|
}, |
|
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
wrap: function wrap(name, glyphs, charstrings, subrs, properties) { |
|
|
|
wrap: function wrap(name, glyphs, charstrings, subrs, properties) { |
|
|
|
function stringToArray(str) { |
|
|
|
var fields = { |
|
|
|
var array = []; |
|
|
|
"header": "\x01\x00\x04\x04", // major version, minor version, header size, offset size
|
|
|
|
for (var i = 0; i < str.length; ++i) |
|
|
|
|
|
|
|
array[i] = str.charCodeAt(i); |
|
|
|
"names": this.createCFFIndexHeader([name]), |
|
|
|
|
|
|
|
|
|
|
|
return array; |
|
|
|
"topDict": (function topDict(self) { |
|
|
|
|
|
|
|
return function() { |
|
|
|
|
|
|
|
var dict = |
|
|
|
|
|
|
|
"\x00\x01\x01\x01\x30" + |
|
|
|
|
|
|
|
"\xf8\x1b\x00" + // version
|
|
|
|
|
|
|
|
"\xf8\x1b\x01" + // Notice
|
|
|
|
|
|
|
|
"\xf8\x1b\x02" + // FullName
|
|
|
|
|
|
|
|
"\xf8\x1b\x03" + // FamilyName
|
|
|
|
|
|
|
|
"\xf8\x1b\x04" + // Weight
|
|
|
|
|
|
|
|
"\x1c\x00\x00\x10"; // Encoding
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var boundingBox = properties.bbox; |
|
|
|
|
|
|
|
for (var i = 0; i < boundingBox.length; i++) |
|
|
|
|
|
|
|
dict += self.encodeNumber(boundingBox[i]); |
|
|
|
|
|
|
|
dict += "\x05"; // FontBBox;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var offset = fields.header.length + |
|
|
|
|
|
|
|
fields.names.length + |
|
|
|
|
|
|
|
(dict.length + (4 + 4 + 7)) + |
|
|
|
|
|
|
|
fields.strings.length + |
|
|
|
|
|
|
|
fields.globalSubrs.length; |
|
|
|
|
|
|
|
dict += self.encodeNumber(offset) + "\x0f"; // Charset
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
offset = offset + (glyphs.length * 2) + 1; |
|
|
|
|
|
|
|
dict += self.encodeNumber(offset) + "\x11"; // Charstrings
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
dict += self.encodeNumber(fields.private.length); |
|
|
|
|
|
|
|
var offset = offset + fields.charstrings.length; |
|
|
|
|
|
|
|
dict += self.encodeNumber(offset) + "\x12"; // Private
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return 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([]), |
|
|
|
|
|
|
|
|
|
|
|
var cff = new Uint8Array(kMaxFontFileSize); |
|
|
|
"charset": (function charset(self) { |
|
|
|
var currentOffset = 0; |
|
|
|
var charset = "\x00"; // Encoding
|
|
|
|
|
|
|
|
|
|
|
|
// Font header (major version, minor version, header size, offset size)
|
|
|
|
var count = glyphs.length; |
|
|
|
var header = "\x01\x00\x04\x04"; |
|
|
|
for (var i = 0; i < count; i++) { |
|
|
|
currentOffset += header.length; |
|
|
|
var index = CFFStrings.indexOf(charstrings[i].glyph.glyph); |
|
|
|
cff.set(stringToArray(header)); |
|
|
|
// Some characters like asterikmath && circlecopyrt are missing from the
|
|
|
|
|
|
|
|
// original strings, for the moment let's map them to .notdef and see
|
|
|
|
// Names Index
|
|
|
|
// later if it cause any problems
|
|
|
|
var nameIndex = stringToArray(this.createCFFIndexHeader([name])); |
|
|
|
|
|
|
|
cff.set(nameIndex, currentOffset); |
|
|
|
|
|
|
|
currentOffset += nameIndex.length; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Calculate strings before writing the TopDICT index in order
|
|
|
|
|
|
|
|
// to calculate correct relative offsets for storing 'charset'
|
|
|
|
|
|
|
|
// and 'charstrings' data
|
|
|
|
|
|
|
|
var version = ""; |
|
|
|
|
|
|
|
var notice = ""; |
|
|
|
|
|
|
|
var fullName = ""; |
|
|
|
|
|
|
|
var familyName = ""; |
|
|
|
|
|
|
|
var weight = ""; |
|
|
|
|
|
|
|
var strings = [version, notice, fullName, |
|
|
|
|
|
|
|
familyName, weight]; |
|
|
|
|
|
|
|
var stringsIndex = stringToArray(this.createCFFIndexHeader(strings)); |
|
|
|
|
|
|
|
var stringsDataLength = stringsIndex.length; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Create the global subroutines index
|
|
|
|
|
|
|
|
var globalSubrsIndex = stringToArray(this.createCFFIndexHeader([])); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Fill the charset header (first byte is the encoding)
|
|
|
|
|
|
|
|
var charset = [0x00]; |
|
|
|
|
|
|
|
var glyphsCount = glyphs.length; |
|
|
|
|
|
|
|
for (var i = 0; i < glyphsCount; i++) { |
|
|
|
|
|
|
|
var index = CFFStrings.indexOf(charstrings[i].glyph); |
|
|
|
|
|
|
|
if (index == -1) |
|
|
|
if (index == -1) |
|
|
|
index = CFFStrings.length + strings.indexOf(charstrings[i].glyph); |
|
|
|
index = 0; |
|
|
|
|
|
|
|
|
|
|
|
var bytes = FontsUtils.integerToBytes(index, 2); |
|
|
|
var bytes = FontsUtils.integerToBytes(index, 2); |
|
|
|
charset.push(bytes[0]); |
|
|
|
charset += String.fromCharCode(bytes[0]) + String.fromCharCode(bytes[1]); |
|
|
|
charset.push(bytes[1]); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return charset; |
|
|
|
|
|
|
|
})(this), |
|
|
|
|
|
|
|
|
|
|
|
var charstringsIndex = stringToArray(this.createCFFIndexHeader([[0x8B, 0x0E]].concat(glyphs), true)); |
|
|
|
"charstrings": this.createCFFIndexHeader([[0x8B, 0x0E]].concat(glyphs), true), |
|
|
|
|
|
|
|
|
|
|
|
//Top Dict Index
|
|
|
|
"private": (function(self) { |
|
|
|
var topDictIndex = [ |
|
|
|
var data = |
|
|
|
0x00, 0x01, 0x01, 0x01, 0x30, |
|
|
|
"\x8b\x14" + // defaultWidth
|
|
|
|
248, 27, 0, // version
|
|
|
|
"\x8b\x15" + // nominalWidth
|
|
|
|
248, 28, 1, // Notice
|
|
|
|
"\x8b\x0a" + // StdHW
|
|
|
|
248, 29, 2, // FullName
|
|
|
|
"\x8b\x0a" + // StdVW
|
|
|
|
248, 30, 3, // FamilyName
|
|
|
|
"\x8b\x8b\x0c\x0c" + // StemSnapH
|
|
|
|
248, 31, 4 // Weight
|
|
|
|
"\x8b\x8b\x0c\x0d"; // StemSnapV
|
|
|
|
]; |
|
|
|
data += self.encodeNumber(data.length + 4) + "\x13"; // Subrs offset
|
|
|
|
|
|
|
|
|
|
|
|
var fontBBox = properties.bbox; |
|
|
|
return data; |
|
|
|
for (var i = 0; i < fontBBox.length; i++) |
|
|
|
})(this), |
|
|
|
topDictIndex = topDictIndex.concat(stringToArray(this.encodeNumber(fontBBox[i]))); |
|
|
|
|
|
|
|
topDictIndex.push(5) // FontBBox;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var charsetOffset = currentOffset + |
|
|
|
|
|
|
|
(topDictIndex.length + (4 + 4 + 4 + 7)) + |
|
|
|
|
|
|
|
stringsIndex.length + |
|
|
|
|
|
|
|
globalSubrsIndex.length; |
|
|
|
|
|
|
|
topDictIndex = topDictIndex.concat(stringToArray(this.encodeNumber(charsetOffset))); |
|
|
|
|
|
|
|
topDictIndex.push(15); // charset
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
topDictIndex = topDictIndex.concat([28, 0, 0, 16]) // Encoding
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var charstringsOffset = charsetOffset + (glyphsCount * 2) + 1; |
|
|
|
|
|
|
|
topDictIndex = topDictIndex.concat(stringToArray(this.encodeNumber(charstringsOffset))); |
|
|
|
|
|
|
|
topDictIndex.push(17); // charstrings
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
topDictIndex = topDictIndex.concat([28, 0, 55]) |
|
|
|
|
|
|
|
var privateOffset = charstringsOffset + charstringsIndex.length; |
|
|
|
|
|
|
|
topDictIndex = topDictIndex.concat(stringToArray(this.encodeNumber(privateOffset))); |
|
|
|
|
|
|
|
topDictIndex.push(18); // Private
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var indexes = [ |
|
|
|
|
|
|
|
topDictIndex, stringsIndex, |
|
|
|
|
|
|
|
globalSubrsIndex, charset, |
|
|
|
|
|
|
|
charstringsIndex |
|
|
|
|
|
|
|
]; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (var i = 0; i < indexes.length; i++) { |
|
|
|
"localSubrs": this.createCFFIndexHeader(subrs, true) |
|
|
|
var index = indexes[i]; |
|
|
|
}; |
|
|
|
cff.set(index, currentOffset); |
|
|
|
fields.topDict = fields.topDict(); |
|
|
|
currentOffset += index.length; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Private Data
|
|
|
|
|
|
|
|
var defaultWidth = stringToArray(this.encodeNumber(0)); |
|
|
|
|
|
|
|
var privateData = [].concat( |
|
|
|
|
|
|
|
defaultWidth, [20], |
|
|
|
|
|
|
|
[139, 21], // nominalWidth
|
|
|
|
|
|
|
|
[ |
|
|
|
|
|
|
|
119, 159, 248, 97, 159, 247, 87, 159, 6, |
|
|
|
|
|
|
|
30, 10, 3, 150, 37, 255, 12, 9, |
|
|
|
|
|
|
|
139, 12, |
|
|
|
|
|
|
|
10, 172, 10, |
|
|
|
|
|
|
|
172, 150, 143, 146, 150, 146, 12, 12, |
|
|
|
|
|
|
|
247, 32, 11, |
|
|
|
|
|
|
|
247, 10, 161, 147, 154, 150, 143, 12, 13, |
|
|
|
|
|
|
|
139, 12, 14, |
|
|
|
|
|
|
|
28, 0, 55, 19 // Subrs offset
|
|
|
|
|
|
|
|
]); |
|
|
|
|
|
|
|
cff.set(privateData, currentOffset); |
|
|
|
|
|
|
|
currentOffset += privateData.length; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Local subrs
|
|
|
|
|
|
|
|
var subrsData = stringToArray(this.createCFFIndexHeader(subrs, true)); |
|
|
|
|
|
|
|
cff.set(subrsData, currentOffset); |
|
|
|
|
|
|
|
currentOffset += subrsData.length; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var fontData = []; |
|
|
|
|
|
|
|
for (var i = 0; i < currentOffset; i++) |
|
|
|
|
|
|
|
fontData.push(cff[i]); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return fontData; |
|
|
|
var cff = []; |
|
|
|
|
|
|
|
for (var index in fields) { |
|
|
|
|
|
|
|
var field = fields[index]; |
|
|
|
|
|
|
|
for (var i = 0; i < field.length; i++) |
|
|
|
|
|
|
|
cff.push(field.charCodeAt(i)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return cff; |
|
|
|
} |
|
|
|
} |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|