Merge pull request #53 from vingtetun/master
Merge TTF font rewriting to pass the font sanitization pass.
This commit is contained in:
commit
5585c6a5fe
102
fonts.js
102
fonts.js
@ -103,7 +103,7 @@ var Font = (function () {
|
|||||||
|
|
||||||
// If the font is to be ignored, register it like an already loaded font
|
// If the font is to be ignored, register it like an already loaded font
|
||||||
// to avoid the cost of waiting for it be be loaded by the platform.
|
// to avoid the cost of waiting for it be be loaded by the platform.
|
||||||
if (properties.ignore || properties.type == "TrueType" || kDisableFonts) {
|
if (properties.ignore || kDisableFonts) {
|
||||||
Fonts[name] = {
|
Fonts[name] = {
|
||||||
data: file,
|
data: file,
|
||||||
loading: false,
|
loading: false,
|
||||||
@ -242,7 +242,7 @@ var Font = (function () {
|
|||||||
return ranges;
|
return ranges;
|
||||||
};
|
};
|
||||||
|
|
||||||
function createCMAPTable(glyphs) {
|
function createCMapTable(glyphs) {
|
||||||
var ranges = getRanges(glyphs);
|
var ranges = getRanges(glyphs);
|
||||||
|
|
||||||
var headerSize = (12 * 2 + (ranges.length * 4 * 2));
|
var headerSize = (12 * 2 + (ranges.length * 4 * 2));
|
||||||
@ -274,7 +274,7 @@ var Font = (function () {
|
|||||||
var bias = 0;
|
var bias = 0;
|
||||||
for (var i = 0; i < segCount - 1; i++) {
|
for (var i = 0; i < segCount - 1; i++) {
|
||||||
var range = ranges[i];
|
var range = ranges[i];
|
||||||
var start = range[0];
|
var start = range[0];
|
||||||
var end = range[1];
|
var end = range[1];
|
||||||
var delta = (((start - 1) - bias) ^ 0xffff) + 1;
|
var delta = (((start - 1) - bias) ^ 0xffff) + 1;
|
||||||
bias += (end - start + 1);
|
bias += (end - start + 1);
|
||||||
@ -284,8 +284,8 @@ var Font = (function () {
|
|||||||
idDeltas += string16(delta);
|
idDeltas += string16(delta);
|
||||||
idRangeOffsets += string16(0);
|
idRangeOffsets += string16(0);
|
||||||
|
|
||||||
for (var j = start; j <= end; j++)
|
for (var j = 0; j < range.length; j++)
|
||||||
glyphsIds += String.fromCharCode(j);
|
glyphsIds += String.fromCharCode(range[j]);
|
||||||
}
|
}
|
||||||
|
|
||||||
startCount += "\xFF\xFF";
|
startCount += "\xFF\xFF";
|
||||||
@ -368,11 +368,11 @@ var Font = (function () {
|
|||||||
var length = FontsUtils.bytesToInteger(file.getBytes(4));
|
var length = FontsUtils.bytesToInteger(file.getBytes(4));
|
||||||
|
|
||||||
// Read the table associated data
|
// Read the table associated data
|
||||||
var currentPosition = file.pos;
|
var previousPosition = file.pos;
|
||||||
file.pos = file.start + offset;
|
file.pos = file.start ? file.start : 0;
|
||||||
|
file.skip(offset);
|
||||||
var data = file.getBytes(length);
|
var data = file.getBytes(length);
|
||||||
file.pos = currentPosition;
|
file.pos = previousPosition;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
tag: tag,
|
tag: tag,
|
||||||
@ -393,6 +393,76 @@ var Font = (function () {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function replaceCMapTable(cmap, font, properties) {
|
||||||
|
var version = FontsUtils.bytesToInteger(font.getBytes(2));
|
||||||
|
var numTables = FontsUtils.bytesToInteger(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));
|
||||||
|
|
||||||
|
if ((format == 0 && numTables == 1) ||
|
||||||
|
(format == 6 && numTables == 1 && !properties.encoding.empty)) {
|
||||||
|
// Format 0 alone is not allowed by the sanitizer so let's rewrite
|
||||||
|
// that to a 3-1-4 Unicode BMP table
|
||||||
|
var charset = properties.charset;
|
||||||
|
var glyphs = [];
|
||||||
|
for (var j = 0; j < charset.length; j++) {
|
||||||
|
glyphs.push({
|
||||||
|
unicode: GlyphsUnicode[charset[j]] || 0
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
cmap.data = createCMapTable(glyphs);
|
||||||
|
} else if (format == 6 && numTables == 1) {
|
||||||
|
// Format 6 is a 2-bytes dense mapping, which means the font data
|
||||||
|
// lives glue together even if they are pretty far in the unicode
|
||||||
|
// 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 glyphs = [];
|
||||||
|
var min = 0xffff, max = 0;
|
||||||
|
for (var j = 0; j < entryCount; j++) {
|
||||||
|
var charcode = FontsUtils.bytesToInteger(font.getBytes(2));
|
||||||
|
glyphs.push(charcode);
|
||||||
|
|
||||||
|
if (charcode < min)
|
||||||
|
min = charcode;
|
||||||
|
if (charcode > max)
|
||||||
|
max = charcode;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Since Format 6 is a dense array, check for gaps
|
||||||
|
for (var j = min; j < max; j++) {
|
||||||
|
if (glyphs.indexOf(j) == -1)
|
||||||
|
glyphs.push(j);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var j = 0; j < glyphs.length; j++)
|
||||||
|
glyphs[j] = { unicode: glyphs[j] + firstCode };
|
||||||
|
|
||||||
|
var ranges= getRanges(glyphs);
|
||||||
|
assert(ranges.length == 1, "Got " + ranges.length + " ranges in a dense array");
|
||||||
|
|
||||||
|
var encoding = properties.encoding;
|
||||||
|
var denseRange = ranges[0];
|
||||||
|
var start = denseRange[0];
|
||||||
|
var end = denseRange[1];
|
||||||
|
var index = firstCode;
|
||||||
|
for (var j = start; j <= end; j++)
|
||||||
|
encoding[index++] = glyphs[j - firstCode - 1].unicode;
|
||||||
|
cmap.data = createCMapTable(glyphs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Check that required tables are present
|
// Check that required tables are present
|
||||||
var requiredTables = [ "OS/2", "cmap", "head", "hhea",
|
var requiredTables = [ "OS/2", "cmap", "head", "hhea",
|
||||||
"hmtx", "maxp", "name", "post" ];
|
"hmtx", "maxp", "name", "post" ];
|
||||||
@ -448,18 +518,8 @@ var Font = (function () {
|
|||||||
data: OS2
|
data: OS2
|
||||||
});
|
});
|
||||||
|
|
||||||
// If the font is missing a OS/2 table it's could be an old mac font
|
|
||||||
// without a 3-1-4 Unicode BMP table, so let's rewrite it.
|
|
||||||
var charset = properties.charset;
|
|
||||||
var glyphs = [];
|
|
||||||
for (var i = 0; i < charset.length; i++) {
|
|
||||||
glyphs.push({
|
|
||||||
unicode: GlyphsUnicode[charset[i]]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Replace the old CMAP table with a shiny new one
|
// Replace the old CMAP table with a shiny new one
|
||||||
cmap.data = createCMAPTable(glyphs);
|
replaceCMapTable(cmap, font, properties);
|
||||||
|
|
||||||
// Rewrite the 'post' table if needed
|
// Rewrite the 'post' table if needed
|
||||||
if (!post) {
|
if (!post) {
|
||||||
@ -599,7 +659,7 @@ var Font = (function () {
|
|||||||
var charstrings = font.getOrderedCharStrings(properties.glyphs);
|
var charstrings = font.getOrderedCharStrings(properties.glyphs);
|
||||||
|
|
||||||
/** CMAP */
|
/** CMAP */
|
||||||
cmap = createCMAPTable(charstrings);
|
cmap = createCMapTable(charstrings);
|
||||||
createTableEntry(otf, offsets, "cmap", cmap);
|
createTableEntry(otf, offsets, "cmap", cmap);
|
||||||
|
|
||||||
/** HEAD */
|
/** HEAD */
|
||||||
|
22
pdf.js
22
pdf.js
@ -2362,7 +2362,7 @@ var CanvasGraphics = (function() {
|
|||||||
// Fonts with an embedded cmap but without any assignment in
|
// Fonts with an embedded cmap but without any assignment in
|
||||||
// it are not yet supported, so ask the fonts loader to ignore
|
// it are not yet supported, so ask the fonts loader to ignore
|
||||||
// them to not pay a stupid one sec latence.
|
// them to not pay a stupid one sec latence.
|
||||||
var ignoreFont = true;
|
var ignoreFont = false;
|
||||||
|
|
||||||
var encodingMap = {};
|
var encodingMap = {};
|
||||||
var charset = [];
|
var charset = [];
|
||||||
@ -2406,20 +2406,24 @@ var CanvasGraphics = (function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (fontDict.has("ToUnicode")) {
|
} else if (fontDict.has("ToUnicode")) {
|
||||||
|
encodingMap = {empty: true};
|
||||||
var cmapObj = xref.fetchIfRef(fontDict.get("ToUnicode"));
|
var cmapObj = xref.fetchIfRef(fontDict.get("ToUnicode"));
|
||||||
if (IsName(cmapObj)) {
|
if (IsName(cmapObj)) {
|
||||||
error("ToUnicode file cmap translation not implemented");
|
error("ToUnicode file cmap translation not implemented");
|
||||||
} else if (IsStream(cmapObj)) {
|
} else if (IsStream(cmapObj)) {
|
||||||
var encoding = Encodings["WinAnsiEncoding"];
|
var encoding = Encodings["WinAnsiEncoding"];
|
||||||
var firstChar = xref.fetchIfRef(fontDict.get("FirstChar"));
|
var firstChar = xref.fetchIfRef(fontDict.get("FirstChar"));
|
||||||
for (var i = firstChar; i < encoding.length; i++)
|
|
||||||
encodingMap[i] = new Name(encoding[i]);
|
|
||||||
|
|
||||||
var tokens = [];
|
var tokens = [];
|
||||||
var token = "";
|
var token = "";
|
||||||
|
|
||||||
var buffer = cmapObj.ensureBuffer ? cmapObj.ensureBuffer() : cmapObj;
|
var length = cmapObj.length;
|
||||||
var cmap = cmapObj.getBytes(buffer.byteLength);
|
if (cmapObj instanceof FlateStream) {
|
||||||
|
cmapObj.readBlock();
|
||||||
|
length = cmapObj.bufferLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
var cmap = cmapObj.getBytes(length);
|
||||||
for (var i =0; i < cmap.length; i++) {
|
for (var i =0; i < cmap.length; i++) {
|
||||||
var byte = cmap[i];
|
var byte = cmap[i];
|
||||||
if (byte == 0x20 || byte == 0x0A || byte == 0x3C || byte == 0x3E) {
|
if (byte == 0x20 || byte == 0x0A || byte == 0x3C || byte == 0x3E) {
|
||||||
@ -2446,8 +2450,10 @@ var CanvasGraphics = (function() {
|
|||||||
var code = parseInt("0x" + tokens[j+2]);
|
var code = parseInt("0x" + tokens[j+2]);
|
||||||
|
|
||||||
for (var k = startRange; k <= endRange; k++) {
|
for (var k = startRange; k <= endRange; k++) {
|
||||||
encodingMap[k] = GlyphsUnicode[encoding[code]];
|
// The encoding mapping table will be filled
|
||||||
charset.push(encoding[code++]);
|
// later during the building phase
|
||||||
|
//encodingMap[k] = GlyphsUnicode[encoding[code]];
|
||||||
|
charset.push(encoding[code++] || ".notdef");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -2752,7 +2758,7 @@ var CanvasGraphics = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.current.fontSize = size;
|
this.current.fontSize = size;
|
||||||
this.ctx.font = this.current.fontSize +'px "' + fontName + '"';
|
this.ctx.font = this.current.fontSize +'px "' + fontName + '", Symbol';
|
||||||
},
|
},
|
||||||
setTextRenderingMode: function(mode) {
|
setTextRenderingMode: function(mode) {
|
||||||
TODO("text rendering mode");
|
TODO("text rendering mode");
|
||||||
|
Loading…
Reference in New Issue
Block a user