Add some code to make (the first one only...) font pass the sanitizer check
This commit is contained in:
parent
066e4c45e0
commit
1f7aaf7b50
224
PDFFont.js
224
PDFFont.js
@ -1,3 +1,5 @@
|
|||||||
|
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
|
||||||
|
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||||
|
|
||||||
var kMaxFontFileSize = 100000;
|
var kMaxFontFileSize = 100000;
|
||||||
|
|
||||||
@ -56,13 +58,18 @@ var Stack = function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
var Base64Encoder = {
|
var Base64Encoder = {
|
||||||
encode: function(aData) {
|
encode: function(aFontName, aData) {
|
||||||
var str = [];
|
var str = [];
|
||||||
var count = aData.length;
|
var count = aData.length;
|
||||||
for (var i = 0; i < count; i++)
|
for (var i = 0; i < count; i++)
|
||||||
str.push(aData.getChar ? aData.getChar() : String.fromCharCode(aData[i]));
|
str.push(aData.getChar ? aData.getChar() : String.fromCharCode(aData[i]));
|
||||||
|
|
||||||
return window.btoa(str.join(""));
|
// Add the css rule to the document
|
||||||
|
var fontData = window.btoa(str.join(""));
|
||||||
|
var url = "url(data:font/otf;base64," + fontData + ");";
|
||||||
|
document.styleSheets[0].insertRule("@font-face { font-family: '" + aFontName + "'; src: " + url + " }", 0);
|
||||||
|
|
||||||
|
return fontData;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -78,12 +85,8 @@ var TrueTypeFont = function(aFontName, aFontFile) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dump("Loading a TrueType font: " + aFontName);
|
dump("Loading a TrueType font: " + aFontName);
|
||||||
var fontData = Base64Encoder.encode(aFontFile);
|
var fontData = Base64Encoder.encode(aFontName, aFontFile);
|
||||||
Fonts.set(aFontName, fontData);
|
Fonts.set(aFontName, fontData);
|
||||||
|
|
||||||
// Add the css rule
|
|
||||||
var url = "url(data:font/ttf;base64," + fontData + ");";
|
|
||||||
document.styleSheets[0].insertRule("@font-face { font-family: '" + aFontName + "'; src: " + url + " }", 0);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var Type1Parser = function(aAsciiStream, aBinaryStream) {
|
var Type1Parser = function(aAsciiStream, aBinaryStream) {
|
||||||
@ -739,13 +742,9 @@ var Type1Font = function(aFontName, aFontFile) {
|
|||||||
var fontName = this.parser.parse();
|
var fontName = this.parser.parse();
|
||||||
var font = Fonts.get(fontName);
|
var font = Fonts.get(fontName);
|
||||||
var fontData = this.convertToOTF(this.convertToCFF(font), font);
|
var fontData = this.convertToOTF(this.convertToCFF(font), font);
|
||||||
fontData = Base64Encoder.encode(fontData);
|
fontData = Base64Encoder.encode(aFontName, fontData);
|
||||||
Fonts.set(aFontName, fontData);
|
Fonts.set(aFontName, fontData);
|
||||||
|
|
||||||
// Add the css rule
|
|
||||||
var url = "url(data:font/otf;base64," + fontData + ");";
|
|
||||||
document.styleSheets[0].insertRule("@font-face { font-family: '" + aFontName + "'; src: " + url + " }", 0);
|
|
||||||
|
|
||||||
var end = Date.now();
|
var end = Date.now();
|
||||||
log("Time to parse font is:" + (end - start));
|
log("Time to parse font is:" + (end - start));
|
||||||
}
|
}
|
||||||
@ -1082,19 +1081,9 @@ Type1Font.prototype = {
|
|||||||
return data;
|
return data;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getMaxPower2: function(aNumber) {
|
||||||
createOpenTypeHeader: function(aNumTables) {
|
|
||||||
// sfnt version (4 bytes)
|
|
||||||
var version = [0x4F, 0x54, 0x54, 0X4F];
|
|
||||||
|
|
||||||
// numTables (2 bytes)
|
|
||||||
var numTables = aNumTables;
|
|
||||||
|
|
||||||
// searchRange (2bytes)
|
|
||||||
// XXX oh man this is dirty, there's probably something obvious to do to
|
|
||||||
// quickly get the maximum power of 2 value...
|
|
||||||
var maxPower = 0;
|
var maxPower = 0;
|
||||||
var value = numTables;
|
var value = aNumber;
|
||||||
while (value >= 2) {
|
while (value >= 2) {
|
||||||
value /= 2;
|
value /= 2;
|
||||||
maxPower++;
|
maxPower++;
|
||||||
@ -1103,10 +1092,22 @@ Type1Font.prototype = {
|
|||||||
value = 2;
|
value = 2;
|
||||||
for (var i = 1; i < maxPower; i++)
|
for (var i = 1; i < maxPower; i++)
|
||||||
value *= 2;
|
value *= 2;
|
||||||
var searchRange = value * 16;
|
|
||||||
|
return value;
|
||||||
|
},
|
||||||
|
|
||||||
|
createOpenTypeHeader: function(aNumTables) {
|
||||||
|
// sfnt version (4 bytes)
|
||||||
|
var version = [0x4F, 0x54, 0x54, 0X4F];
|
||||||
|
|
||||||
|
// numTables (2 bytes)
|
||||||
|
var numTables = aNumTables;
|
||||||
|
|
||||||
|
// searchRange (2 bytes)
|
||||||
|
var searchRange = this.getMaxPower2(numTables) * 16;
|
||||||
|
|
||||||
// entrySelector (2 bytes)
|
// entrySelector (2 bytes)
|
||||||
var entrySelector = Math.log(value) / Math.log(2);
|
var entrySelector = Math.log(this.getMaxPower2(numTables)) / Math.log(2);
|
||||||
|
|
||||||
// rangeShift (2 bytes)
|
// rangeShift (2 bytes)
|
||||||
var rangeShift = numTables * 16 - searchRange;
|
var rangeShift = numTables * 16 - searchRange;
|
||||||
@ -1210,36 +1211,150 @@ Type1Font.prototype = {
|
|||||||
/** CMAP */
|
/** CMAP */
|
||||||
var charstrings = this.getOrderedCharStrings(aFont);
|
var charstrings = this.getOrderedCharStrings(aFont);
|
||||||
|
|
||||||
var cmap = [
|
if (false) {
|
||||||
0x00, 0x00, // version
|
var cmap = [
|
||||||
0x00, 0x01, // numTables
|
0x00, 0x00, // version
|
||||||
0x00, 0x01, // platformID
|
0x00, 0x01, // numTables
|
||||||
0x00, 0x00, // encodingID
|
0x00, 0x01, // platformID
|
||||||
0x00, 0x00, 0x00, 0x0C, //offset
|
0x00, 0x00, // encodingID
|
||||||
0x00, 0x00,
|
0x00, 0x00, 0x00, 0x0C, //offset
|
||||||
0x01, 0x06,
|
0x00, 0x00,
|
||||||
0x00, 0x00
|
0x01, 0x06,
|
||||||
];
|
0x00, 0x00
|
||||||
|
];
|
||||||
|
|
||||||
var data = [];
|
var data = [];
|
||||||
for (var i = 0; i < 262; i++) {
|
for (var i = 0; i < 262; i++) {
|
||||||
data.push(0x00);
|
data.push(0x00);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < charstrings.length; i++) {
|
||||||
|
var glyph = charstrings[i].glyph;
|
||||||
|
if (glyph == ".notdef")
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var pos = GlyphsUnicode[glyph];
|
||||||
|
if (!pos)
|
||||||
|
error(charstrings[i].glyph + " does not have an entry in the glyphs table");
|
||||||
|
var b1 = parseInt("0x" + pos[0] + pos[1]);
|
||||||
|
var b2 = parseInt("0x" + pos[2] + pos[3]);
|
||||||
|
var num = this.bytesToInteger([b1, b2]);
|
||||||
|
data[num] = i + 1;
|
||||||
|
}
|
||||||
|
cmap = cmap.concat(data);
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
var data = new Array(1000);
|
||||||
|
for (var i = 0; i < charstrings.length; i++) {
|
||||||
|
var glyph = charstrings[i].glyph;
|
||||||
|
if (glyph == ".notdef")
|
||||||
|
continue;
|
||||||
|
|
||||||
for (var i = 0; i < charstrings.length; i++) {
|
var pos = GlyphsUnicode[glyph];
|
||||||
var glyph = charstrings[i].glyph;
|
if (!pos)
|
||||||
if (glyph == ".notdef")
|
error(charstrings[i].glyph + " does not have an entry in the glyphs table");
|
||||||
continue;
|
var b1 = parseInt("0x" + pos[0] + pos[1]);
|
||||||
|
var b2 = parseInt("0x" + pos[2] + pos[3]);
|
||||||
|
var num = this.bytesToInteger([b1, b2]);
|
||||||
|
data[num] = i + 1;
|
||||||
|
}
|
||||||
|
|
||||||
var pos = GlyphsUnicode[glyph];
|
var ranges = [];
|
||||||
if (!pos)
|
var range = [];
|
||||||
error(charstrings[i].glyph + " does not have an entry in the glyphs table");
|
for (var i = 0; i < data.length; i++) {
|
||||||
var b1 = parseInt("0x" + pos[0] + pos[1]);
|
var char = data[i];
|
||||||
var b2 = parseInt("0x" + pos[2] + pos[3]);
|
if (char) {
|
||||||
var num = this.bytesToInteger([b1, b2]);
|
range.push(i);
|
||||||
data[num] = i + 1;
|
} else if (range.length) {
|
||||||
|
//log("create a new range of " + range.length + " chars width min: " + range[0] + " to max: " + range[range.length - 1]);
|
||||||
|
ranges.push(range.slice());
|
||||||
|
range = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var cmap = [];
|
||||||
|
var segCount = ranges.length + 1;
|
||||||
|
|
||||||
|
var segCount2 = segCount * 2;
|
||||||
|
var searchRange = this.getMaxPower2(segCount) * 2;
|
||||||
|
var searchEntry = Math.log(segCount) / Math.log(2);
|
||||||
|
var rangeShift = 2 * segCount - searchRange;
|
||||||
|
cmap = cmap.concat(this.integerToBytes(segCount2, 2));
|
||||||
|
cmap = cmap.concat(this.integerToBytes(searchRange, 2));
|
||||||
|
cmap = cmap.concat(this.integerToBytes(searchEntry, 2));
|
||||||
|
cmap = cmap.concat(this.integerToBytes(rangeShift, 2));
|
||||||
|
|
||||||
|
// End characters code with an additional 0xFFFF to finish the array
|
||||||
|
var endCodes = [];
|
||||||
|
for (var i = 0; i < ranges.length; i++) {
|
||||||
|
var range = ranges[i];
|
||||||
|
cmap = cmap.concat(this.integerToBytes(range[range.length - 1], 2));
|
||||||
|
};
|
||||||
|
cmap = cmap.concat([0xFF, 0xFF]);
|
||||||
|
|
||||||
|
// reserved pad
|
||||||
|
cmap = cmap.concat([0x00, 0x00]);
|
||||||
|
|
||||||
|
// Start characters code with an additional 0xFFFF to finish the array
|
||||||
|
for (var i = 0; i < ranges.length; i++) {
|
||||||
|
var range = ranges[i];
|
||||||
|
cmap = cmap.concat(this.integerToBytes(range[0], 2));
|
||||||
|
};
|
||||||
|
cmap = cmap.concat([0xFF, 0xFF]);
|
||||||
|
|
||||||
|
|
||||||
|
// Fill idDelta
|
||||||
|
var idDelta = [];
|
||||||
|
var delta = 0;
|
||||||
|
var p = 1;
|
||||||
|
for (var i = 0; i < ranges.length; i++) {
|
||||||
|
var range = ranges[i];
|
||||||
|
var start = range[0];
|
||||||
|
var end = range[range.length - 1];
|
||||||
|
var diff = end - start;
|
||||||
|
var delta = -(start - p);
|
||||||
|
|
||||||
|
var value = this.integerToBytes(-delta, 2);
|
||||||
|
value[0] ^= 0xFF;
|
||||||
|
value[1] ^= 0xFF;
|
||||||
|
value[1] += 1;
|
||||||
|
|
||||||
|
cmap = cmap.concat([value[0], value[1]]);
|
||||||
|
delta -= range.length;
|
||||||
|
p += range.length;
|
||||||
|
};
|
||||||
|
cmap = cmap.concat([0x00, 0x01]);
|
||||||
|
|
||||||
|
|
||||||
|
// Fill id Offsets with 0x00
|
||||||
|
for (var i = 0; i < ranges.length; i++) {
|
||||||
|
var range = ranges[i];
|
||||||
|
cmap = cmap.concat([0x00, 0x00]);
|
||||||
|
};
|
||||||
|
cmap = cmap.concat([0x00, 0x00]);
|
||||||
|
|
||||||
|
|
||||||
|
var cmapHeader = [
|
||||||
|
0x00, 0x00, // version
|
||||||
|
0x00, 0x01, // numTables
|
||||||
|
0x00, 0x03, // platformID
|
||||||
|
0x00, 0x01, // encodingID
|
||||||
|
0x00, 0x00, 0x00, 0x0C, // start of the table record
|
||||||
|
0x00, 0x04 // format
|
||||||
|
];
|
||||||
|
cmapHeader = cmapHeader.concat(this.integerToBytes(cmap.length + 6, 2)); // length
|
||||||
|
cmapHeader = cmapHeader.concat(0x00, 0x00); // language
|
||||||
|
|
||||||
|
// Fill up data!
|
||||||
|
for (var i = 0; i < ranges.length; i++) {
|
||||||
|
var range = ranges[i];
|
||||||
|
for (var j = 0; j < range.length; j++) {
|
||||||
|
cmap = cmap.concat(range[j]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
cmap = cmapHeader.concat(cmap);
|
||||||
}
|
}
|
||||||
cmap = cmap.concat(data);
|
|
||||||
|
|
||||||
var tableEntry = this.createTableEntry("cmap", virtualOffset, cmap);
|
var tableEntry = this.createTableEntry("cmap", virtualOffset, cmap);
|
||||||
otf.set(tableEntry, currentOffset);
|
otf.set(tableEntry, currentOffset);
|
||||||
@ -1321,7 +1436,7 @@ Type1Font.prototype = {
|
|||||||
|
|
||||||
var maxp = [
|
var maxp = [
|
||||||
0x00, 0x00, 0x50, 0x00, // Version number
|
0x00, 0x00, 0x50, 0x00, // Version number
|
||||||
].concat(this.integerToBytes(charstrings.length, 2)); // Num of glyphs
|
].concat(this.integerToBytes(charstrings.length + 1, 2)); // Num of glyphs (+1 to pass the sanitizer...)
|
||||||
|
|
||||||
var tableEntry = this.createTableEntry("maxp", virtualOffset, maxp);
|
var tableEntry = this.createTableEntry("maxp", virtualOffset, maxp);
|
||||||
otf.set(tableEntry, currentOffset);
|
otf.set(tableEntry, currentOffset);
|
||||||
@ -1344,12 +1459,13 @@ Type1Font.prototype = {
|
|||||||
|
|
||||||
/** POST */
|
/** POST */
|
||||||
|
|
||||||
|
// XXX get those info from the Font dict!
|
||||||
var post = [
|
var post = [
|
||||||
0x00, 0x03, 0x00, 0x00, // Version number
|
0x00, 0x03, 0x00, 0x00, // Version number
|
||||||
0x00, 0x00, 0x01, 0x00, // italicAngle
|
0x00, 0x00, 0x01, 0x00, // italicAngle
|
||||||
0x00, 0x00, // underlinePosition
|
0x00, 0x00, // underlinePosition
|
||||||
0x00, 0x00, // underlineThickness
|
0x00, 0x00, // underlineThickness
|
||||||
0x00, 0x00, 0x00, 0x01, // isFixedPitch
|
0x00, 0x00, 0x00, 0x00, // isFixedPitch
|
||||||
0x00, 0x00, 0x00, 0x00, // minMemType42
|
0x00, 0x00, 0x00, 0x00, // minMemType42
|
||||||
0x00, 0x00, 0x00, 0x00, // maxMemType42
|
0x00, 0x00, 0x00, 0x00, // maxMemType42
|
||||||
0x00, 0x00, 0x00, 0x00, // minMemType1
|
0x00, 0x00, 0x00, 0x00, // minMemType1
|
||||||
@ -1375,7 +1491,7 @@ Type1Font.prototype = {
|
|||||||
for (var i = 0; i < currentOffset; i++)
|
for (var i = 0; i < currentOffset; i++)
|
||||||
fontData.push(otf[i]);
|
fontData.push(otf[i]);
|
||||||
|
|
||||||
//writeToFile(data, "/tmp/pdf.js.otf");
|
writeToFile(fontData, "/tmp/pdf.js.otf");
|
||||||
return fontData;
|
return fontData;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user