diff --git a/fonts.js b/fonts.js
index 607e2aab9..b3961c8fc 100755
--- a/fonts.js
+++ b/fonts.js
@@ -372,7 +372,7 @@ function getUnicodeRangeFor(value) {
* var type1Font = new Font("MyFontName", binaryFile, propertiesObject);
* type1Font.bind();
*/
-var Font = (function() {
+var Font = (function Font() {
var constructor = function font_constructor(name, file, properties) {
this.name = name;
this.textMatrix = properties.textMatrix || IDENTITY_MATRIX;
@@ -531,6 +531,19 @@ var Font = (function() {
}
ranges.push([start, end]);
}
+
+ // Removes duplicate ranges
+ for (var i = ranges.length - 1; i > 0; i--) {
+ var range = [];
+ var range1 = ranges[i];
+ var range2 = ranges[i - 1];
+ if (range1[0] == range2[1]) {
+ range2[0] = range2[0] - 1;
+ range2[1] = range1[1];
+ ranges.splice(i, 1);
+ }
+ }
+
return ranges;
};
@@ -790,21 +803,57 @@ var Font = (function() {
};
function replaceCMapTable(cmap, font, properties) {
- font.pos = (font.start ? font.start : 0) + cmap.length;
+ var start = (font.start ? font.start : 0) + cmap.length;
+ font.pos = start;
var version = int16(font.getBytes(2));
- var numTables = int16(font.getBytes(2));
+ var numRecords = int16(font.getBytes(2));
- for (var i = 0; i < numTables; i++) {
- var platformID = int16(font.getBytes(2));
- var encodingID = int16(font.getBytes(2));
- var offset = int32(font.getBytes(4));
+ var records = [];
+ for (var i = 0; i < numRecords; i++) {
+ records.push({
+ platformID: int16(font.getBytes(2)),
+ encodingID: int16(font.getBytes(2)),
+ offset: int32(font.getBytes(4))
+ });
+ };
+
+
+ for (var i = 0; i < numRecords; i++) {
+ var table = records[i];
+ font.pos = start + table.offset;
+
var format = int16(font.getBytes(2));
var length = int16(font.getBytes(2));
var language = int16(font.getBytes(2));
-
- if ((format == 0 && numTables == 1) ||
- (format == 6 && numTables == 1 && !properties.encoding.empty)) {
+
+ if (format == 0 && numRecords > 1) {
+ // Characters below 0x20 are controls characters that are hardcoded
+ // into the platform so if some characters in the font are assigned
+ // under this limit they will not be displayed so let's rewrite the
+ // CMap.
+ var map = [];
+ var rewrite = false;
+ for (var j = 0; j < 256; j++) {
+ var index = font.getByte();
+ if (index != 0) {
+ map.push(index);
+ if (j < 0x20)
+ rewrite = true;
+ }
+ }
+
+ if (rewrite) {
+ var glyphs = [];
+ for (var j = 0x20; j < 256; j++) {
+ // TODO do not hardcode WinAnsiEncoding
+ var unicode = GlyphsUnicode[Encodings["WinAnsiEncoding"][j]];
+ glyphs.push({ unicode: unicode });
+ }
+ cmap.data = createCMapTable(glyphs, true);
+ }
+ } else if ((format == 0 && numRecords == 1) ||
+ (format == 6 && numRecords == 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
TODO('Use an other source of informations than ' +
@@ -818,7 +867,7 @@ var Font = (function() {
}
cmap.data = createCMapTable(glyphs);
- } else if (format == 6 && numTables == 1) {
+ } else if (format == 6 && numRecords == 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
@@ -871,10 +920,7 @@ var Font = (function() {
var header = readOpenTypeHeader(font);
var numTables = header.numTables;
- // This keep a reference to the CMap and the post tables since they can
- // be rewritted
- var cmap, post, nameTable, maxp;
-
+ var cmap, maxp;
var tables = [];
for (var i = 0; i < numTables; i++) {
var table = readTableEntry(font);
@@ -882,10 +928,6 @@ var Font = (function() {
if (index != -1) {
if (table.tag == 'cmap')
cmap = table;
- else if (table.tag == 'post')
- post = table;
- else if (table.tag == 'name')
- nameTable = table;
else if (table.tag == 'maxp')
maxp = table;
@@ -894,136 +936,127 @@ var Font = (function() {
tables.push(table);
}
- // If any tables are still in the array this means some required
- // tables are missing, which means that we need to rebuild the
- // font in order to pass the sanitizer.
- if (requiredTables.length && requiredTables[0] == 'OS/2') {
- // Create a new file to hold the new version of our truetype with a new
- // header and new offsets
- var ttf = new Uint8Array(kMaxFontFileSize);
+ // Create a new file to hold the new version of our truetype with a new
+ // header and new offsets
+ var ttf = new Uint8Array(kMaxFontFileSize);
- // The offsets object holds at the same time a representation of where
- // to write the table entry information about a table and another offset
- // representing the offset where to put the actual data of a particular
- // table
- var numTables = header.numTables + requiredTables.length;
- var offsets = {
- currentOffset: 0,
- virtualOffset: numTables * (4 * 4)
- };
+ // The offsets object holds at the same time a representation of where
+ // to write the table entry information about a table and another offset
+ // representing the offset where to put the actual data of a particular
+ // table
+ var numTables = header.numTables + requiredTables.length;
+ var offsets = {
+ currentOffset: 0,
+ virtualOffset: numTables * (4 * 4)
+ };
- // The new numbers of tables will be the last one plus the num
- // of missing tables
- createOpenTypeHeader('\x00\x01\x00\x00', ttf, offsets, numTables);
+ // The new numbers of tables will be the last one plus the num
+ // of missing tables
+ createOpenTypeHeader('\x00\x01\x00\x00', ttf, offsets, numTables);
- // Insert the missing table
+ if (requiredTables.indexOf('OS/2') != -1) {
tables.push({
tag: 'OS/2',
data: stringToArray(createOS2Table(properties))
});
+ }
- // Replace the old CMAP table with a shiny new one
- if (properties.type == 'CIDFontType2') {
- // Type2 composite fonts map characters directly to glyphs so the cmap
- // table must be replaced.
+ // Replace the old CMAP table with a shiny new one
+ if (properties.type == 'CIDFontType2') {
+ // Type2 composite fonts map characters directly to glyphs so the cmap
+ // table must be replaced.
- var glyphs = [];
- var charset = properties.charset;
- if (!charset.length) {
- // PDF did not contain a GIDMap for the font so create an identity cmap
+ var glyphs = [];
+ var charset = properties.charset;
+ if (!charset.length) {
+ // PDF did not contain a GIDMap for the font so create an identity cmap
- // First get the number of glyphs from the maxp table
- font.pos = (font.start ? font.start : 0) + maxp.length;
- var version = int16(font.getBytes(4));
- var numGlyphs = int16(font.getBytes(2));
+ // First get the number of glyphs from the maxp table
+ font.pos = (font.start ? font.start : 0) + maxp.length;
+ var version = int16(font.getBytes(4));
+ var numGlyphs = int16(font.getBytes(2));
- // Now create an identity mapping
- for (var i = 1; i < numGlyphs; i++) {
- glyphs.push({
- unicode: i
- });
- }
- } else {
- for (var i = 1; i < charset.length; i++) {
- var index = charset.indexOf(i);
- if (index != -1) {
- glyphs.push({
- unicode: index
- });
- } else {
- break;
- }
- }
- }
-
- if (!cmap) {
- // Font did not contain a cmap
- tables.push({
- tag: 'cmap',
- data: createCMapTable(glyphs)
- })
- } else {
- cmap.data = createCMapTable(glyphs);
+ // Now create an identity mapping
+ for (var i = 1; i < numGlyphs; i++) {
+ glyphs.push({
+ unicode: i
+ });
}
} else {
- replaceCMapTable(cmap, font, properties);
+ for (var i = 1; i < charset.length; i++) {
+ var index = charset.indexOf(i);
+ if (index != -1) {
+ glyphs.push({
+ unicode: index
+ });
+ } else {
+ break;
+ }
+ }
}
-
- // Rewrite the 'post' table if needed
- if (!post) {
+
+ if (!cmap) {
+ // Font did not contain a cmap
tables.push({
- tag: 'post',
- data: stringToArray(createPostTable(properties))
- });
+ tag: 'cmap',
+ data: createCMapTable(glyphs)
+ })
+ } else {
+ cmap.data = createCMapTable(glyphs);
}
-
- // Rewrite the 'name' table if needed
- if (!nameTable) {
- tables.push({
- tag: 'name',
- data: stringToArray(createNameTable(this.name))
- });
- }
-
- // Tables needs to be written by ascendant alphabetic order
- tables.sort(function tables_sort(a, b) {
- return (a.tag > b.tag) - (a.tag < b.tag);
- });
-
- // rewrite the tables but tweak offsets
- for (var i = 0; i < tables.length; i++) {
- var table = tables[i];
- var data = [];
-
- var tableData = table.data;
- for (var j = 0; j < tableData.length; j++)
- data.push(tableData[j]);
- createTableEntry(ttf, offsets, table.tag, data);
- }
-
- // Add the table datas
- for (var i = 0; i < tables.length; i++) {
- var table = tables[i];
- var tableData = table.data;
- ttf.set(tableData, offsets.currentOffset);
- offsets.currentOffset += tableData.length;
-
- // 4-byte aligned data
- while (offsets.currentOffset & 3)
- offsets.currentOffset++;
- }
-
- var fontData = [];
- for (var i = 0; i < offsets.currentOffset; i++)
- fontData.push(ttf[i]);
-
- return fontData;
- } else if (requiredTables.length) {
- error('Table ' + requiredTables[0] +
- ' is missing from the TrueType font');
+ } else {
+ replaceCMapTable(cmap, font, properties);
}
- return font.getBytes();
+ // Rewrite the 'post' table if needed
+ if (requiredTables.indexOf('post') != -1) {
+ tables.push({
+ tag: 'post',
+ data: stringToArray(createPostTable(properties))
+ });
+ }
+
+ // Rewrite the 'name' table if needed
+ if (requiredTables.indexOf('name') != -1) {
+ tables.push({
+ tag: 'name',
+ data: stringToArray(createNameTable(this.name))
+ });
+ }
+
+ // Tables needs to be written by ascendant alphabetic order
+ tables.sort(function tables_sort(a, b) {
+ return (a.tag > b.tag) - (a.tag < b.tag);
+ });
+
+ // rewrite the tables but tweak offsets
+ for (var i = 0; i < tables.length; i++) {
+ var table = tables[i];
+ var data = [];
+
+ var tableData = table.data;
+ for (var j = 0; j < tableData.length; j++)
+ data.push(tableData[j]);
+ createTableEntry(ttf, offsets, table.tag, data);
+ }
+
+ // Add the table datas
+ for (var i = 0; i < tables.length; i++) {
+ var table = tables[i];
+ var tableData = table.data;
+ ttf.set(tableData, offsets.currentOffset);
+ offsets.currentOffset += tableData.length;
+
+ // 4-byte aligned data
+ while (offsets.currentOffset & 3)
+ offsets.currentOffset++;
+ }
+
+ var fontData = [];
+ for (var i = 0; i < offsets.currentOffset; i++)
+ fontData.push(ttf[i]);
+
+ return fontData;
},
convert: function font_convert(fontName, font, properties) {
diff --git a/web/viewer.html b/web/viewer.html
index df9604db4..8caa40f3e 100644
--- a/web/viewer.html
+++ b/web/viewer.html
@@ -8,6 +8,7 @@
+