From 65b8158c3454a7ff0720b2d8f1827316943ff585 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Mon, 13 Jun 2011 03:35:56 +0200 Subject: [PATCH] CMAP creation code is now more readable --- PDFFont.js | 115 ++++++++++++++++++++++++----------------------------- 1 file changed, 52 insertions(+), 63 deletions(-) diff --git a/PDFFont.js b/PDFFont.js index 8cddb2360..479b05add 100644 --- a/PDFFont.js +++ b/PDFFont.js @@ -147,6 +147,7 @@ Font.prototype = { for (var i = 0; i < aGlyphs.length; i++) data[aGlyphs[i].unicode] = i + 1; + // Separate the glyphs into continuous range of codes, aka segment. var ranges = []; var range = []; for (var i = 0; i < data.length; i++) { @@ -164,80 +165,68 @@ Font.prototype = { } - var cmap = []; - var segCount = ranges.length + 1; + // The size in bytes of the header is equal to the size of the + // different fields * length of a short + (size of the 4 parallels arrays + // describing segments * length of a short). + var headerSize = (12 * 2 + (ranges.length * 4 * 2)); + var segCount = ranges.length + 1; var segCount2 = segCount * 2; var searchRange = FontsUtils.getMaxPower2(segCount) * 2; var searchEntry = Math.log(segCount) / Math.log(2); var rangeShift = 2 * segCount - searchRange; - cmap = cmap.concat(FontsUtils.integerToBytes(segCount2, 2)); - cmap = cmap.concat(FontsUtils.integerToBytes(searchRange, 2)); - cmap = cmap.concat(FontsUtils.integerToBytes(searchEntry, 2)); - cmap = cmap.concat(FontsUtils.integerToBytes(rangeShift, 2)); + var cmap = [].concat( + [ + 0x00, 0x00, // version + 0x00, 0x01, // numTables + 0x00, 0x03, // platformID + 0x00, 0x01, // encodingID + 0x00, 0x00, 0x00, 0x0C, // start of the table record + 0x00, 0x04 // format + ], + FontsUtils.integerToBytes(headerSize, 2), // length + [0x00, 0x00], // language + FontsUtils.integerToBytes(segCount2, 2), + FontsUtils.integerToBytes(searchRange, 2), + FontsUtils.integerToBytes(searchEntry, 2), + FontsUtils.integerToBytes(rangeShift, 2) + ); - // End characters code with an additional 0xFFFF to finish the array - for (var i = 0; i < ranges.length; i++) { + // Fill up the 4 parallel arrays describing the segments. + var startCount = []; + var endCount = []; + var idDeltas = []; + var idRangeOffsets = []; + var glyphsIdsArray = []; + var bias = 0; + for (var i = 0; i < segCount - 1; i++) { var range = ranges[i]; - cmap = cmap.concat(FontsUtils.integerToBytes(range[range.length - 1], 2)); - }; - cmap = cmap.concat([0xFF, 0xFF]); + var start = FontsUtils.integerToBytes(range[0], 2); + var end = FontsUtils.integerToBytes(range[range.length - 1], 2); - // reserved pad - cmap = cmap.concat([0x00, 0x00]); + var delta = FontsUtils.integerToBytes(((range[0] - 1) - bias) % 65536, 2); + bias += range.length; - // 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(FontsUtils.integerToBytes(range[0], 2)); - }; - cmap = cmap.concat([0xFF, 0xFF]); + // deltas are signed shorts + delta[0] ^= 0xFF; + delta[1] ^= 0xFF; + delta[1] += 1; - // Fill idDelta - var delta = 0; - var p = 0; - for (var i = 0; i < ranges.length; i++) { - var range = ranges[i]; - var start = range[0]; - var delta = ((start - 1) - p) % 65536; + startCount.push(start[0], start[1]); + endCount.push(end[0], end[1]); + idDeltas.push(delta[0], delta[1]); + idRangeOffsets.push(0x00, 0x00); - var value = FontsUtils.integerToBytes(delta, 2); - value[0] ^= 0xFF; - value[1] ^= 0xFF; - value[1] += 1; - cmap = cmap.concat([value[0], value[1]]); - - 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(FontsUtils.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); - return cmap; + glyphsIdsArray.push(range[j]); + } + startCount.push(0xFF, 0xFF); + endCount.push(0xFF, 0xFF); + idDeltas.push(0x00, 0x01); + idRangeOffsets.push(0x00, 0x00); + + return cmap.concat(endCount, [0x00, 0x00], startCount, + idDeltas, idRangeOffsets, glyphsIdsArray); }, cover: function font_cover(aFont) { @@ -442,7 +431,7 @@ Font.prototype = { for (var i = 0; i < currentOffset; i++) fontData.push(otf[i]); - //writeToFile(fontData, "/tmp/pdf.js." + fontCount + ".otf"); + writeToFile(fontData, "/tmp/pdf.js." + fontCount + ".otf"); return fontData; } };