|
|
|
@ -466,6 +466,29 @@ var Font = (function () {
@@ -466,6 +466,29 @@ var Font = (function () {
|
|
|
|
|
return array; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
function int16(bytes) { |
|
|
|
|
return (bytes[0] << 8) + (bytes[1] & 0xff); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
function int32(bytes) { |
|
|
|
|
return (bytes[0] << 24) + (bytes[1] << 16) + |
|
|
|
|
(bytes[2] << 8) + (bytes[3] & 0xff); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
function getMaxPower2(number) { |
|
|
|
|
var maxPower = 0; |
|
|
|
|
var value = number; |
|
|
|
|
while (value >= 2) { |
|
|
|
|
value /= 2; |
|
|
|
|
maxPower++; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
value = 2; |
|
|
|
|
for (var i = 1; i < maxPower; i++) |
|
|
|
|
value *= 2; |
|
|
|
|
return value; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
function string16(value) { |
|
|
|
|
return String.fromCharCode((value >> 8) & 0xff) + |
|
|
|
|
String.fromCharCode(value & 0xff); |
|
|
|
@ -486,7 +509,7 @@ var Font = (function () {
@@ -486,7 +509,7 @@ var Font = (function () {
|
|
|
|
|
header += string16(numTables); |
|
|
|
|
|
|
|
|
|
// searchRange (2 bytes)
|
|
|
|
|
var tablesMaxPower2 = FontsUtils.getMaxPower2(numTables); |
|
|
|
|
var tablesMaxPower2 = getMaxPower2(numTables); |
|
|
|
|
var searchRange = tablesMaxPower2 * 16; |
|
|
|
|
header += string16(searchRange); |
|
|
|
|
|
|
|
|
@ -507,7 +530,7 @@ var Font = (function () {
@@ -507,7 +530,7 @@ var Font = (function () {
|
|
|
|
|
|
|
|
|
|
// length
|
|
|
|
|
var length = data.length; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Per spec tables must be 4-bytes align so add padding as needed
|
|
|
|
|
while (data.length & 3) |
|
|
|
|
data.push(0x00); |
|
|
|
@ -518,7 +541,7 @@ var Font = (function () {
@@ -518,7 +541,7 @@ var Font = (function () {
|
|
|
|
|
// checksum
|
|
|
|
|
var checksum = 0; |
|
|
|
|
for (var i = 0; i < length; i+=4) |
|
|
|
|
checksum += FontsUtils.bytesToInteger([data[i], data[i+1], data[i+2], data[i+3]]); |
|
|
|
|
checksum += int16([data[i], data[i+1], data[i+2], data[i+3]]); |
|
|
|
|
|
|
|
|
|
var tableEntry = tag + string32(checksum) + string32(offset) + string32(length); |
|
|
|
|
tableEntry = stringToArray(tableEntry); |
|
|
|
@ -565,7 +588,7 @@ var Font = (function () {
@@ -565,7 +588,7 @@ var Font = (function () {
|
|
|
|
|
var headerSize = (12 * 2 + (ranges.length * 5 * 2)); |
|
|
|
|
var segCount = ranges.length + 1; |
|
|
|
|
var segCount2 = segCount * 2; |
|
|
|
|
var searchRange = FontsUtils.getMaxPower2(segCount) * 2; |
|
|
|
|
var searchRange = getMaxPower2(segCount) * 2; |
|
|
|
|
var searchEntry = Math.log(segCount) / Math.log(2); |
|
|
|
|
var rangeShift = 2 * segCount - searchRange; |
|
|
|
|
|
|
|
|
@ -712,9 +735,9 @@ var Font = (function () {
@@ -712,9 +735,9 @@ var Font = (function () {
|
|
|
|
|
String.fromCharCode(tag[2]) + |
|
|
|
|
String.fromCharCode(tag[3]); |
|
|
|
|
|
|
|
|
|
var checksum = FontsUtils.bytesToInteger(file.getBytes(4)); |
|
|
|
|
var offset = FontsUtils.bytesToInteger(file.getBytes(4)); |
|
|
|
|
var length = FontsUtils.bytesToInteger(file.getBytes(4)); |
|
|
|
|
var checksum = int32(file.getBytes(4)); |
|
|
|
|
var offset = int32(file.getBytes(4)); |
|
|
|
|
var length = int32(file.getBytes(4)); |
|
|
|
|
|
|
|
|
|
// Read the table associated data
|
|
|
|
|
var previousPosition = file.pos; |
|
|
|
@ -735,26 +758,26 @@ var Font = (function () {
@@ -735,26 +758,26 @@ var Font = (function () {
|
|
|
|
|
function readOpenTypeHeader(ttf) { |
|
|
|
|
return { |
|
|
|
|
version: ttf.getBytes(4), |
|
|
|
|
numTables: FontsUtils.bytesToInteger(ttf.getBytes(2)), |
|
|
|
|
searchRange: FontsUtils.bytesToInteger(ttf.getBytes(2)), |
|
|
|
|
entrySelector: FontsUtils.bytesToInteger(ttf.getBytes(2)), |
|
|
|
|
rangeShift: FontsUtils.bytesToInteger(ttf.getBytes(2)) |
|
|
|
|
numTables: int16(ttf.getBytes(2)), |
|
|
|
|
searchRange: int16(ttf.getBytes(2)), |
|
|
|
|
entrySelector: int16(ttf.getBytes(2)), |
|
|
|
|
rangeShift: int16(ttf.getBytes(2)) |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
function replaceCMapTable(cmap, font, properties) { |
|
|
|
|
font.pos = (font.start ? font.start : 0) + cmap.length; |
|
|
|
|
|
|
|
|
|
var version = FontsUtils.bytesToInteger(font.getBytes(2)); |
|
|
|
|
var numTables = FontsUtils.bytesToInteger(font.getBytes(2)); |
|
|
|
|
var version = int16(font.getBytes(2)); |
|
|
|
|
var numTables = int16(font.getBytes(2)); |
|
|
|
|
|
|
|
|
|
for (var i = 0; i < numTables; i++) { |
|
|
|
|
var platformID = FontsUtils.bytesToInteger(font.getBytes(2)); |
|
|
|
|
var encodingID = FontsUtils.bytesToInteger(font.getBytes(2)); |
|
|
|
|
var offset = FontsUtils.bytesToInteger(font.getBytes(4)); |
|
|
|
|
var format = FontsUtils.bytesToInteger(font.getBytes(2)); |
|
|
|
|
var length = FontsUtils.bytesToInteger(font.getBytes(2)); |
|
|
|
|
var language = FontsUtils.bytesToInteger(font.getBytes(2)); |
|
|
|
|
var platformID = int16(font.getBytes(2)); |
|
|
|
|
var encodingID = int16(font.getBytes(2)); |
|
|
|
|
var offset = int32(font.getBytes(4)); |
|
|
|
|
var format = int16(font.getBytes(2)); |
|
|
|
|
var length = int16(font.getBytes(2)); |
|
|
|
|
var language = int16(font.getBytes(2)); |
|
|
|
|
|
|
|
|
|
if ((format == 0 && numTables == 1) || |
|
|
|
|
(format == 6 && numTables == 1 && !properties.encoding.empty)) { |
|
|
|
@ -776,13 +799,13 @@ var Font = (function () {
@@ -776,13 +799,13 @@ var Font = (function () {
|
|
|
|
|
// table. (This looks weird, so I can have missed something), this
|
|
|
|
|
// works on Linux but seems to fails on Mac so let's rewrite the
|
|
|
|
|
// cmap table to a 3-1-4 style
|
|
|
|
|
var firstCode = FontsUtils.bytesToInteger(font.getBytes(2)); |
|
|
|
|
var entryCount = FontsUtils.bytesToInteger(font.getBytes(2)); |
|
|
|
|
var firstCode = int16(font.getBytes(2)); |
|
|
|
|
var entryCount = int16(font.getBytes(2)); |
|
|
|
|
|
|
|
|
|
var glyphs = []; |
|
|
|
|
var min = 0xffff, max = 0; |
|
|
|
|
for (var j = 0; j < entryCount; j++) { |
|
|
|
|
var charcode = FontsUtils.bytesToInteger(font.getBytes(2)); |
|
|
|
|
var charcode = int16(font.getBytes(2)); |
|
|
|
|
glyphs.push(charcode); |
|
|
|
|
|
|
|
|
|
if (charcode < min) |
|
|
|
@ -882,7 +905,7 @@ var Font = (function () {
@@ -882,7 +905,7 @@ var Font = (function () {
|
|
|
|
|
|
|
|
|
|
// Tables needs to be written by ascendant alphabetic order
|
|
|
|
|
tables.sort(function tables_sort(a, b) { |
|
|
|
|
return a.tag > b.tag; |
|
|
|
|
return (a.tag > b.tag) - (a.tag < b.tag); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
// rewrite the tables but tweak offsets
|
|
|
|
@ -921,8 +944,6 @@ var Font = (function () {
@@ -921,8 +944,6 @@ var Font = (function () {
|
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
convert: function font_convert(fontName, font, properties) { |
|
|
|
|
var otf = new Uint8Array(kMaxFontFileSize); |
|
|
|
|
|
|
|
|
|
function createNameTable(name) { |
|
|
|
|
// All the strings of the name table should be an odd number of bytes
|
|
|
|
|
if (name.length % 2) |
|
|
|
@ -985,7 +1006,7 @@ var Font = (function () {
@@ -985,7 +1006,7 @@ var Font = (function () {
|
|
|
|
|
nameTable += strings.join("") + stringsUnicode.join(""); |
|
|
|
|
return nameTable; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function isFixedPitch(glyphs) { |
|
|
|
|
for (var i = 0; i < glyphs.length - 1; i++) { |
|
|
|
|
if (glyphs[i] != glyphs[i+1]) |
|
|
|
@ -994,46 +1015,34 @@ var Font = (function () {
@@ -994,46 +1015,34 @@ var Font = (function () {
|
|
|
|
|
return true; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
// Required Tables
|
|
|
|
|
var CFF = |
|
|
|
|
font.data, // PostScript Font Program
|
|
|
|
|
OS2, // OS/2 and Windows Specific metrics
|
|
|
|
|
cmap, // Character to glyphs mapping
|
|
|
|
|
head, // Font header
|
|
|
|
|
hhea, // Horizontal header
|
|
|
|
|
hmtx, // Horizontal metrics
|
|
|
|
|
maxp, // Maximum profile
|
|
|
|
|
name, // Naming tables
|
|
|
|
|
post; // PostScript informations
|
|
|
|
|
var tables = [CFF, OS2, cmap, head, hhea, hmtx, maxp, name, post]; |
|
|
|
|
|
|
|
|
|
// The offsets object holds at the same time a representation of where
|
|
|
|
|
// to write the table entry information about a table and another offset
|
|
|
|
|
// representing the offset where to draw the actual data of a particular
|
|
|
|
|
// table
|
|
|
|
|
var kRequiredTablesCount = 9; |
|
|
|
|
var offsets = { |
|
|
|
|
currentOffset: 0, |
|
|
|
|
virtualOffset: tables.length * (4 * 4) |
|
|
|
|
virtualOffset: 9 * (4 * 4) |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
// It there is only one font, offset table is the first bytes of the file
|
|
|
|
|
createOpenTypeHeader("\x4F\x54\x54\x4F", otf, offsets, tables.length); |
|
|
|
|
|
|
|
|
|
/** CFF */ |
|
|
|
|
createTableEntry(otf, offsets, "CFF ", CFF); |
|
|
|
|
var otf = new Uint8Array(kMaxFontFileSize); |
|
|
|
|
createOpenTypeHeader("\x4F\x54\x54\x4F", otf, offsets, 9); |
|
|
|
|
|
|
|
|
|
/** OS/2 */ |
|
|
|
|
var charstrings = font.charstrings; |
|
|
|
|
properties.fixedPitch = isFixedPitch(charstrings); |
|
|
|
|
OS2 = stringToArray(createOS2Table(properties)); |
|
|
|
|
createTableEntry(otf, offsets, "OS/2", OS2); |
|
|
|
|
var fields = { |
|
|
|
|
// PostScript Font Program
|
|
|
|
|
"CFF ": font.data, |
|
|
|
|
|
|
|
|
|
/** CMAP */ |
|
|
|
|
cmap = createCMapTable(charstrings.slice()); |
|
|
|
|
createTableEntry(otf, offsets, "cmap", cmap); |
|
|
|
|
// OS/2 and Windows Specific metrics
|
|
|
|
|
"OS/2": stringToArray(createOS2Table(properties)), |
|
|
|
|
|
|
|
|
|
/** HEAD */ |
|
|
|
|
head = stringToArray( |
|
|
|
|
// Character to glyphs mapping
|
|
|
|
|
"cmap": createCMapTable(charstrings.slice()), |
|
|
|
|
|
|
|
|
|
// Font header
|
|
|
|
|
"head": (function() { |
|
|
|
|
return stringToArray( |
|
|
|
|
"\x00\x01\x00\x00" + // Version number
|
|
|
|
|
"\x00\x00\x10\x00" + // fontRevision
|
|
|
|
|
"\x00\x00\x00\x00" + // checksumAdjustement
|
|
|
|
@ -1050,63 +1059,59 @@ var Font = (function () {
@@ -1050,63 +1059,59 @@ var Font = (function () {
|
|
|
|
|
"\x00\x11" + // lowestRecPPEM
|
|
|
|
|
"\x00\x00" + // fontDirectionHint
|
|
|
|
|
"\x00\x00" + // indexToLocFormat
|
|
|
|
|
"\x00\x00" // glyphDataFormat
|
|
|
|
|
); |
|
|
|
|
createTableEntry(otf, offsets, "head", head); |
|
|
|
|
|
|
|
|
|
/** HHEA */ |
|
|
|
|
hhea = stringToArray( |
|
|
|
|
"\x00\x01\x00\x00" + // Version number
|
|
|
|
|
string16(properties.ascent) + // Typographic Ascent
|
|
|
|
|
string16(properties.descent) + // Typographic Descent
|
|
|
|
|
"\x00\x00" + // Line Gap
|
|
|
|
|
"\xFF\xFF" + // advanceWidthMax
|
|
|
|
|
"\x00\x00" + // minLeftSidebearing
|
|
|
|
|
"\x00\x00" + // minRightSidebearing
|
|
|
|
|
"\x00\x00" + // xMaxExtent
|
|
|
|
|
string16(properties.capHeight) + // caretSlopeRise
|
|
|
|
|
string16(Math.tan(properties.italicAngle) * properties.xHeight) + // caretSlopeRun
|
|
|
|
|
"\x00\x00" + // caretOffset
|
|
|
|
|
"\x00\x00" + // -reserved-
|
|
|
|
|
"\x00\x00" + // -reserved-
|
|
|
|
|
"\x00\x00" + // -reserved-
|
|
|
|
|
"\x00\x00" + // -reserved-
|
|
|
|
|
"\x00\x00" + // metricDataFormat
|
|
|
|
|
string16(charstrings.length + 1) // Number of HMetrics
|
|
|
|
|
); |
|
|
|
|
createTableEntry(otf, offsets, "hhea", hhea); |
|
|
|
|
|
|
|
|
|
/** HMTX */ |
|
|
|
|
/* For some reasons, probably related to how the backend handle fonts, |
|
|
|
|
* Linux seems to ignore this file and prefer the data from the CFF itself |
|
|
|
|
* while Windows use this data. So be careful if you hack on Linux and |
|
|
|
|
* have to touch the 'hmtx' table |
|
|
|
|
*/ |
|
|
|
|
hmtx = "\x00\x00\x00\x00"; // Fake .notdef
|
|
|
|
|
for (var i = 0; i < charstrings.length; i++) { |
|
|
|
|
hmtx += string16(charstrings[i].width) + string16(0); |
|
|
|
|
} |
|
|
|
|
hmtx = stringToArray(hmtx); |
|
|
|
|
createTableEntry(otf, offsets, "hmtx", hmtx); |
|
|
|
|
|
|
|
|
|
/** MAXP */ |
|
|
|
|
maxp = "\x00\x00\x50\x00" + // Version number
|
|
|
|
|
string16(charstrings.length + 1); // Num of glyphs
|
|
|
|
|
maxp = stringToArray(maxp); |
|
|
|
|
createTableEntry(otf, offsets, "maxp", maxp); |
|
|
|
|
|
|
|
|
|
/** NAME */ |
|
|
|
|
name = stringToArray(createNameTable(fontName)); |
|
|
|
|
createTableEntry(otf, offsets, "name", name); |
|
|
|
|
|
|
|
|
|
/** POST */ |
|
|
|
|
post = stringToArray(createPostTable(properties)); |
|
|
|
|
createTableEntry(otf, offsets, "post", post); |
|
|
|
|
|
|
|
|
|
// Once all the table entries header are written, dump the data!
|
|
|
|
|
var tables = [CFF, OS2, cmap, head, hhea, hmtx, maxp, name, post]; |
|
|
|
|
for (var i = 0; i < tables.length; i++) { |
|
|
|
|
var table = tables[i]; |
|
|
|
|
"\x00\x00"); // glyphDataFormat
|
|
|
|
|
})(), |
|
|
|
|
|
|
|
|
|
// Horizontal header
|
|
|
|
|
"hhea": (function() { |
|
|
|
|
return stringToArray( |
|
|
|
|
"\x00\x01\x00\x00" + // Version number
|
|
|
|
|
string16(properties.ascent) + // Typographic Ascent
|
|
|
|
|
string16(properties.descent) + // Typographic Descent
|
|
|
|
|
"\x00\x00" + // Line Gap
|
|
|
|
|
"\xFF\xFF" + // advanceWidthMax
|
|
|
|
|
"\x00\x00" + // minLeftSidebearing
|
|
|
|
|
"\x00\x00" + // minRightSidebearing
|
|
|
|
|
"\x00\x00" + // xMaxExtent
|
|
|
|
|
string16(properties.capHeight) + // caretSlopeRise
|
|
|
|
|
string16(Math.tan(properties.italicAngle) * properties.xHeight) + // caretSlopeRun
|
|
|
|
|
"\x00\x00" + // caretOffset
|
|
|
|
|
"\x00\x00" + // -reserved-
|
|
|
|
|
"\x00\x00" + // -reserved-
|
|
|
|
|
"\x00\x00" + // -reserved-
|
|
|
|
|
"\x00\x00" + // -reserved-
|
|
|
|
|
"\x00\x00" + // metricDataFormat
|
|
|
|
|
string16(charstrings.length + 1)); // Number of HMetrics
|
|
|
|
|
})(), |
|
|
|
|
|
|
|
|
|
// Horizontal metrics
|
|
|
|
|
"hmtx": (function() { |
|
|
|
|
var hmtx = "\x00\x00\x00\x00"; // Fake .notdef
|
|
|
|
|
for (var i = 0; i < charstrings.length; i++) { |
|
|
|
|
hmtx += string16(charstrings[i].width) + string16(0); |
|
|
|
|
} |
|
|
|
|
return stringToArray(hmtx); |
|
|
|
|
})(), |
|
|
|
|
|
|
|
|
|
// Maximum profile
|
|
|
|
|
"maxp": (function() { |
|
|
|
|
return stringToArray( |
|
|
|
|
"\x00\x00\x50\x00" + // Version number
|
|
|
|
|
string16(charstrings.length + 1)); // Num of glyphs
|
|
|
|
|
})(), |
|
|
|
|
|
|
|
|
|
// Naming tables
|
|
|
|
|
"name": stringToArray(createNameTable(fontName)), |
|
|
|
|
|
|
|
|
|
// PostScript informations
|
|
|
|
|
"post": stringToArray(createPostTable(properties)) |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
for (var field in fields) |
|
|
|
|
createTableEntry(otf, offsets, field, fields[field]); |
|
|
|
|
|
|
|
|
|
for (var field in fields) { |
|
|
|
|
var table = fields[field]; |
|
|
|
|
otf.set(table, offsets.currentOffset); |
|
|
|
|
offsets.currentOffset += table.length; |
|
|
|
|
} |
|
|
|
@ -1144,54 +1149,6 @@ var Font = (function () {
@@ -1144,54 +1149,6 @@ var Font = (function () {
|
|
|
|
|
return constructor; |
|
|
|
|
})(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* FontsUtils is a static class dedicated to hold codes that are not related |
|
|
|
|
* to fonts in particular and needs to be share between them. |
|
|
|
|
*/ |
|
|
|
|
var FontsUtils = { |
|
|
|
|
_bytesArray: new Uint8Array(4), |
|
|
|
|
integerToBytes: function fu_integerToBytes(value, bytesCount) { |
|
|
|
|
var bytes = this._bytesArray; |
|
|
|
|
|
|
|
|
|
if (bytesCount == 1) { |
|
|
|
|
bytes.set([value]); |
|
|
|
|
return bytes[0]; |
|
|
|
|
} else if (bytesCount == 2) { |
|
|
|
|
bytes.set([value >> 8, value & 0xff]); |
|
|
|
|
return [bytes[0], bytes[1]]; |
|
|
|
|
} else if (bytesCount == 4) { |
|
|
|
|
bytes.set([value >> 24, value >> 16, value >> 8, value]); |
|
|
|
|
return [bytes[0], bytes[1], bytes[2], bytes[3]]; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
error("This number of bytes " + bytesCount + " is not supported"); |
|
|
|
|
return null; |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
bytesToInteger: function fu_bytesToInteger(bytesArray) { |
|
|
|
|
var value = 0; |
|
|
|
|
for (var i = 0; i < bytesArray.length; i++) |
|
|
|
|
value = (value << 8) + bytesArray[i]; |
|
|
|
|
return value; |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
getMaxPower2: function fu_getMaxPower2(number) { |
|
|
|
|
var maxPower = 0; |
|
|
|
|
var value = number; |
|
|
|
|
while (value >= 2) { |
|
|
|
|
value /= 2; |
|
|
|
|
maxPower++; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
value = 2; |
|
|
|
|
for (var i = 1; i < maxPower; i++) |
|
|
|
|
value *= 2; |
|
|
|
|
return value; |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Type1Parser encapsulate the needed code for parsing a Type1 font |
|
|
|
|
* program. |
|
|
|
@ -1638,10 +1595,7 @@ CFF.prototype = {
@@ -1638,10 +1595,7 @@ CFF.prototype = {
|
|
|
|
|
if (count == 0) |
|
|
|
|
return "\x00\x00\x00"; |
|
|
|
|
|
|
|
|
|
var data = ""; |
|
|
|
|
var bytes = FontsUtils.integerToBytes(count, 2); |
|
|
|
|
for (var i = 0; i < bytes.length; i++) |
|
|
|
|
data += String.fromCharCode(bytes[i]); |
|
|
|
|
var data = String.fromCharCode(count >> 8, 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
|
|
|
|
@ -1651,9 +1605,8 @@ CFF.prototype = {
@@ -1651,9 +1605,8 @@ CFF.prototype = {
|
|
|
|
|
// Add another offset after this one because we need a new offset
|
|
|
|
|
var relativeOffset = 1; |
|
|
|
|
for (var i = 0; i < count + 1; i++) { |
|
|
|
|
var bytes = FontsUtils.integerToBytes(relativeOffset, 4); |
|
|
|
|
for (var j = 0; j < bytes.length; j++) |
|
|
|
|
data += String.fromCharCode(bytes[j]); |
|
|
|
|
data += String.fromCharCode(relativeOffset >> 24, relativeOffset >> 16, |
|
|
|
|
relativeOffset >> 8, relativeOffset & 0xff); |
|
|
|
|
|
|
|
|
|
if (objects[i]) |
|
|
|
|
relativeOffset += objects[i].length; |
|
|
|
@ -1703,7 +1656,7 @@ CFF.prototype = {
@@ -1703,7 +1656,7 @@ CFF.prototype = {
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
charstrings.sort(function charstrings_sort(a, b) { |
|
|
|
|
return a.unicode > b.unicode; |
|
|
|
|
return a.unicode - b.unicode; |
|
|
|
|
}); |
|
|
|
|
return charstrings; |
|
|
|
|
}, |
|
|
|
@ -1848,8 +1801,7 @@ CFF.prototype = {
@@ -1848,8 +1801,7 @@ CFF.prototype = {
|
|
|
|
|
if (index == -1) |
|
|
|
|
index = 0; |
|
|
|
|
|
|
|
|
|
var bytes = FontsUtils.integerToBytes(index, 2); |
|
|
|
|
charset += String.fromCharCode(bytes[0]) + String.fromCharCode(bytes[1]); |
|
|
|
|
charset += String.fromCharCode(index >> 8, index & 0xff); |
|
|
|
|
} |
|
|
|
|
return charset; |
|
|
|
|
})(this), |
|
|
|
|