From 5cb2a07b3d224e40874bb9d96173eb6ce2fdc6ab Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Fri, 9 Sep 2011 16:37:56 +0200 Subject: [PATCH] Fix an issue with the vhea/vmtx tables --- fonts.js | 66 ++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 45 insertions(+), 21 deletions(-) diff --git a/fonts.js b/fonts.js index a7fb509d0..32de47c56 100755 --- a/fonts.js +++ b/fonts.js @@ -1032,9 +1032,9 @@ var Font = (function Font() { var end = denseRange[1]; var index = firstCode; for (var j = start; j <= end; j++) { - var code = j - firstCode - 1; + var code = glyphs[j - start]; var mapping = encoding[index] || {}; - mapping.unicode = glyphs[code].unicode; + mapping.unicode = code.unicode; encoding[index++] = mapping; } return cmap.data = createCMapTable(glyphs); @@ -1043,6 +1043,39 @@ var Font = (function Font() { return cmap.data; }; + function sanitizeMetrics(font, header, metrics, numGlyphs) { + if (!header && !metrics) + return; + + // The vhea/vmtx tables are not required, so it happens that + // some fonts embed a vmtx table without a vhea table. In this + // situation the sanitizer assume numOfLongVerMetrics = 1. As + // a result it tries to read numGlyphs - 1 SHORT from the vmtx + // table, and if it is not possible, the font is rejected. + // So remove the vmtx table if there is no vhea table. + if (!header && metrics) { + metrics.data = null; + return; + } + + font.pos = (font.start ? font.start : 0) + header.offset; + font.pos += header.length - 2; + var numOfMetrics = int16(font.getBytes(2)); + + var numOfSidebearings = numGlyphs - numOfMetrics; + var numMissing = numOfSidebearings - + ((hmtx.length - numOfMetrics * 4) >> 1); + if (numMissing > 0) { + font.pos = (font.start ? font.start : 0) + metrics.offset; + var entries = ''; + for (var i = 0; i < hmtx.length; i++) + entries += String.fromCharCode(font.getByte()); + for (var i = 0; i < numMissing; i++) + entries += '\x00\x00'; + metrics.data = stringToArray(entries); + } + }; + // Check that required tables are present var requiredTables = ['OS/2', 'cmap', 'head', 'hhea', 'hmtx', 'maxp', 'name', 'post']; @@ -1050,7 +1083,7 @@ var Font = (function Font() { var header = readOpenTypeHeader(font); var numTables = header.numTables; - var cmap, maxp, hhea, hmtx; + var cmap, maxp, hhea, hmtx, vhea, vmtx; var tables = []; for (var i = 0; i < numTables; i++) { var table = readTableEntry(font); @@ -1066,6 +1099,11 @@ var Font = (function Font() { hmtx = table; requiredTables.splice(index, 1); + } else { + if (table.tag == 'vmtx') + vmtx = table; + else if (table.tag == 'vhea') + vhea = table; } tables.push(table); } @@ -1091,28 +1129,14 @@ var Font = (function Font() { }); } - // Ensure the hmtx tables contains an advance width and a sidebearing - // for the number of glyphs declared in the maxp table + // Ensure the [h/v]mtx tables contains the advance width and + // sidebearings information for numGlyphs in the maxp table font.pos = (font.start ? font.start : 0) + maxp.offset; var version = int16(font.getBytes(4)); var numGlyphs = int16(font.getBytes(2)); - font.pos = (font.start ? font.start : 0) + hhea.offset; - font.pos += hhea.length - 2; - var numOfHMetrics = int16(font.getBytes(2)); - - var numOfSidebearings = numGlyphs - numOfHMetrics; - var numMissing = numOfSidebearings - - ((hmtx.length - numOfHMetrics * 4) >> 1); - if (numMissing > 0) { - font.pos = (font.start ? font.start : 0) + hmtx.offset; - var metrics = ''; - for (var i = 0; i < hmtx.length; i++) - metrics += String.fromCharCode(font.getByte()); - for (var i = 0; i < numMissing; i++) - metrics += '\x00\x00'; - hmtx.data = stringToArray(metrics); - } + sanitizeMetrics(font, hhea, hmtx, numGlyphs); + sanitizeMetrics(font, vhea, vmtx, numGlyphs); // Sanitizer reduces the glyph advanceWidth to the maxAdvanceWidth // Sometimes it's 0. That needs to be fixed