Browse Source

Open the CFF class road for Type1C font

Vivien Nicolas 14 years ago
parent
commit
5cbc6875b3
  1. 134
      fonts.js

134
fonts.js

@ -6,7 +6,7 @@
/** /**
* Maximum file size of the font. * Maximum file size of the font.
*/ */
var kMaxFontFileSize = 40000; var kMaxFontFileSize = 200000;
/** /**
* Maximum time to wait for a font to be loaded by @font-face * Maximum time to wait for a font to be loaded by @font-face
@ -34,7 +34,7 @@ var kDisableFonts = false;
* http://cgit.freedesktop.org/poppler/poppler/tree/poppler/GfxFont.cc#n65 * http://cgit.freedesktop.org/poppler/poppler/tree/poppler/GfxFont.cc#n65
*/ */
var Fonts = (function () { var Fonts = (function Fonts() {
var kScalePrecision = 40; var kScalePrecision = 40;
var fonts = Object.create(null); var fonts = Object.create(null);
var ctx = document.createElement("canvas").getContext("2d"); var ctx = document.createElement("canvas").getContext("2d");
@ -1462,13 +1462,17 @@ var CFF = function(name, file, properties) {
var length1 = file.dict.get("Length1"); var length1 = file.dict.get("Length1");
var length2 = file.dict.get("Length2"); var length2 = file.dict.get("Length2");
file.skip(length1); file.skip(length1);
var eexecBlock = file.getBytes(length2);
// Decrypt the data blocks and retrieve it's content // Decrypt the data blocks and retrieve it's content
var eexecBlock = file.getBytes(length2);
var data = type1Parser.extractFontProgram(eexecBlock); var data = type1Parser.extractFontProgram(eexecBlock);
this.charstrings = this.getOrderedCharStrings(data.charstrings); var charstrings = this.getOrderedCharStrings(data.charstrings);
this.data = this.wrap(name, this.charstrings, data.subrs, properties); var type2Charstrings = this.getType2Charstrings(charstrings);
var subrs = this.getType2Subrs(data.subrs);
this.charstrings = charstrings;
this.data = this.wrap(name, type2Charstrings, this.charstrings, subrs, properties);
}; };
CFF.prototype = { CFF.prototype = {
@ -1546,12 +1550,40 @@ CFF.prototype = {
return charstrings; return charstrings;
}, },
getType2Charstrings: function cff_getType2Charstrings(type1Charstrings) {
var type2Charstrings = [];
var count = type1Charstrings.length;
for (var i = 0; i < count; i++) {
var charstring = type1Charstrings[i].charstring;
type2Charstrings.push(this.flattenCharstring(charstring.slice(), this.commandsMap));
}
return type2Charstrings;
},
getType2Subrs: function cff_getType2Charstrings(type1Subrs) {
var bias = 0;
var count = type1Subrs.length;
if (count < 1240)
bias = 107;
else if (count < 33900)
bias = 1131;
else
bias = 32768;
// Add a bunch of empty subrs to deal with the Type2 bias
var type2Subrs = [];
for (var i = 0; i < bias; i++)
type2Subrs.push([0x0B]);
for (var i = 0; i < count; i++)
type2Subrs.push(this.flattenCharstring(type1Subrs[i], this.commandsMap));
return type2Subrs;
},
/* /*
* Flatten the commands by interpreting the postscript code and replacing * Flatten the commands by interpreting the postscript code and replacing
* every 'callsubr', 'callothersubr' by the real commands. * every 'callsubr', 'callothersubr' by the real commands.
*
* TODO This function also do a string to command number transformation
* that can probably be avoided if the Type1 decodeCharstring code is smarter
*/ */
commandsMap: { commandsMap: {
"hstem": 1, "hstem": 1,
@ -1573,58 +1605,27 @@ CFF.prototype = {
"hvcurveto": 31, "hvcurveto": 31,
}, },
flattenCharstring: function flattenCharstring(charstring) { flattenCharstring: function flattenCharstring(charstring, map) {
var i = 0; for (var i = 0; i < charstring.length; i++) {
while (true) { var command = charstring[i];
var obj = charstring[i]; if (command.charAt) {
if (obj == undefined) { var cmd = map[command];
error("unknow charstring command for " + i + " in " + charstring); assert(cmd, "Unknow command: " + command);
}
if (obj.charAt) {
switch (obj) {
case "endchar":
case "return":
// CharString is ready to be re-encode to commands number at this point
for (var j = 0; j < charstring.length; j++) {
var command = charstring[j];
if (parseFloat(command) == command) {
charstring.splice(j, 1, 28, command >> 8, command);
j+= 2;
} else if (command.charAt) {
var cmd = this.commandsMap[command];
if (!cmd)
error("Unknow command: " + command);
if (IsArray(cmd)) {
charstring.splice(j, 1, cmd[0], cmd[1]);
j += 1;
} else {
charstring[j] = cmd;
}
}
}
return charstring;
default: if (IsArray(cmd)) {
break; charstring.splice(i++, 1, cmd[0], cmd[1]);
} else {
charstring[i] = cmd;
} }
} else {
charstring.splice(i, 1, 28, command >> 8, command & 0xff);
i+= 2;
} }
i++;
} }
error("failing with i = " + i + " in charstring:" + charstring + "(" + charstring.length + ")"); return charstring;
return [];
}, },
wrap: function wrap(name, charstrings, subrs, properties) { wrap: function wrap(name, glyphs, charstrings, subrs, properties) {
// Starts the conversion of the Type1 charstrings to Type2
var glyphs = [];
var glyphsCount = charstrings.length;
for (var i = 0; i < glyphsCount; i++) {
var charstring = charstrings[i].charstring;
glyphs.push(this.flattenCharstring(charstring.slice()));
}
// Create a CFF font data
var cff = new Uint8Array(kMaxFontFileSize); var cff = new Uint8Array(kMaxFontFileSize);
var currentOffset = 0; var currentOffset = 0;
@ -1656,10 +1657,12 @@ CFF.prototype = {
// Fill the charset header (first byte is the encoding) // Fill the charset header (first byte is the encoding)
var charset = [0x00]; var charset = [0x00];
var glyphsCount = glyphs.length;
for (var i = 0; i < glyphsCount; i++) { for (var i = 0; i < glyphsCount; i++) {
var index = CFFStrings.indexOf(charstrings[i].glyph); var index = CFFStrings.indexOf(charstrings[i].glyph);
if (index == -1) if (index == -1)
index = CFFStrings.length + strings.indexOf(charstrings[i].glyph); index = CFFStrings.length + strings.indexOf(charstrings[i].glyph);
var bytes = FontsUtils.integerToBytes(index, 2); var bytes = FontsUtils.integerToBytes(index, 2);
charset.push(bytes[0]); charset.push(bytes[0]);
charset.push(bytes[1]); charset.push(bytes[1]);
@ -1731,28 +1734,9 @@ CFF.prototype = {
cff.set(privateData, currentOffset); cff.set(privateData, currentOffset);
currentOffset += privateData.length; currentOffset += privateData.length;
// Local Subrs
var flattenedSubrs = [];
var bias = 0;
var subrsCount = subrs.length;
if (subrsCount < 1240)
bias = 107;
else if (subrsCount < 33900)
bias = 1131;
else
bias = 32768;
// Add a bunch of empty subrs to deal with the Type2 bias
for (var i = 0; i < bias; i++)
flattenedSubrs.push([0x0B]);
for (var i = 0; i < subrsCount; i++) {
var subr = subrs[i];
flattenedSubrs.push(this.flattenCharstring(subr));
}
var subrsData = this.createCFFIndexHeader(flattenedSubrs, true); // Local subrs
var subrsData = this.createCFFIndexHeader(subrs, true);
cff.set(subrsData, currentOffset); cff.set(subrsData, currentOffset);
currentOffset += subrsData.length; currentOffset += subrsData.length;

Loading…
Cancel
Save