var charStrings = this.parseIndex(topDict.CharStrings);
var charset = this.parseCharsets(topDict.charset,
charStrings.length, strings);
- var hasSupplement = this.parseEncoding(topDict.Encoding, properties,
+ var encoding = this.parseEncoding(topDict.Encoding, properties,
strings, charset);
// The font sanitizer does not support CFF encoding with a
// between gid to glyph, let's overwrite what is declared in
// the top dictionary to let the sanitizer think the font use
// StandardEncoding, that's a lie but that's ok.
- if (hasSupplement)
- bytes[topDict.Encoding] = 0;
+ if (encoding.hasSupplement)
+ bytes[topDict.Encoding] &= 0x7F;
// The CFF specification state that the 'dotsection' command
// (12, 0) is deprecated and treated as a no-op, but all Type2
// charstrings contains info about glyphs (one element per glyph
// containing mappings for {unicode, width})
- var charstrings = this.getCharStrings(charset, charStrings,
+ var charstrings = this.getCharStrings(charset, encoding.encoding,
privateDict, this.properties);
// create the mapping between charstring and glyph id
return data;
},
- getCharStrings: function cff_charstrings(charsets, charStrings,
+ getCharStrings: function cff_charstrings(charsets, encoding,
privateDict, properties) {
var defaultWidth = privateDict['defaultWidthX'];
var charstrings = [];
var differences = properties.differences;
- var index = properties.firstChar || 0;
for (var i = 1; i < charsets.length; i++) {
- var code = -1;
+ var inDifferences;
var glyph = charsets[i];
+ var code;
for (var j = 0; j < differences.length; j++) {
if (differences[j] == glyph) {
- index = j;
- code = differences.indexOf(glyph);
+ code = j;
+ inDifferences = true;
break;
}
}
+ if (!inDifferences) {
+ var code = properties.firstChar + i;
+ for (var s in encoding) {
+ if (encoding[s] == i) {
+ code = s | 0;
+ break;
+ }
+ }
+ }
+
+ if (properties.encoding[code] &&
+ properties.encoding[code].inDifferences)
+ continue;
- var mapping =
- properties.glyphs[glyph] || properties.glyphs[index] || {};
- if (code == -1)
- index = code = mapping.unicode || index;
+ var mapping = properties.glyphs[code] || properties.glyphs[glyph] || {};
+ var unicode = mapping.unicode || code;
- if (code <= 0x1f || (code >= 127 && code <= 255))
- code += kCmapGlyphOffset;
+ if (unicode <= 0x1f || (unicode >= 127 && unicode <= 255))
+ unicode += kCmapGlyphOffset;
- var width = mapping.width;
- properties.glyphs[glyph] = properties.encoding[index] = {
- unicode: code,
- width: isNum(width) ? width : defaultWidth
+ var width = isNum(mapping.width) ? mapping.width : defaultWidth;
+ properties.encoding[code] = {
+ unicode: unicode,
+ width: width,
+ inDifferences: inDifferences
};
charstrings.push({
- unicode: code,
+ unicode: unicode,
width: width,
gid: i
});
- index++;
}
// sort the array by the unicode value
charstrings.sort(function type2CFFGetCharStringsSort(a, b) {
return a.unicode - b.unicode;
});
+
+ // remove duplicates -- they might appear during selection:
+ // properties.glyphs[code] || properties.glyphs[glyph]
+ // TODO make more deterministic
+ var nextUnusedUnicode = kCmapGlyphOffset + 0x0020;
+ var lastUnicode = charstrings[0].unicode, wasModified = false;
+ for (var i = 1; i < charstrings.length; ++i) {
+ if (lastUnicode != charstrings[i].unicode) {
+ lastUnicode = charstrings[i].unicode;
+ continue;
+ }
+ // duplicate found -- changing the unicode for previous one
+ charstrings[i - 1].unicode = nextUnusedUnicode++;
+ wasModified = true;
+ }
+ if (!wasModified)
+ return charstrings;
+
+ // sort the array by the unicode value (again)
+ charstrings.sort(function type2CFFGetCharStringsSort(a, b) {
+ return a.unicode - b.unicode;
+ });
return charstrings;
},
charset) {
var encoding = {};
var bytes = this.bytes;
+ var result = {
+ encoding: encoding,
+ hasSupplement: false
+ };
function readSupplement() {
var supplementsCount = bytes[pos++];
var glyphsCount = bytes[pos++];
for (var i = 1; i <= glyphsCount; i++)
encoding[bytes[pos++]] = i;
-
- if (format & 0x80) {
- readSupplement();
- return true;
- }
break;
case 1:
for (var j = start; j <= start + count; j++)
encoding[j] = gid++;
}
-
- if (format & 0x80) {
- readSupplement();
- return true;
- }
break;
default:
error('Unknow encoding format: ' + format + ' in CFF');
break;
}
+ if (format & 0x80) {
+ readSupplement();
+ result.hasSupplement = true;
+ }
}
- return false;
+ return result;
},
parseCharsets: function cff_parsecharsets(pos, length, strings) {