diff --git a/docs/glyph-inspector.html b/docs/glyph-inspector.html
index cc49e23e..5b809d2b 100644
--- a/docs/glyph-inspector.html
+++ b/docs/glyph-inspector.html
@@ -387,8 +387,12 @@
Free Software
hline('yMin', font.tables.head.yMin);
hline('Ascender', font.tables.hhea.ascender);
hline('Descender', font.tables.hhea.descender);
- hline('Typo Ascender', font.tables.os2.sTypoAscender);
- hline('Typo Descender', font.tables.os2.sTypoDescender);
+
+ // Some PDF-embedded fonts might not have the OS/2 table
+ if (font.tables.os2) {
+ hline('Typo Ascender', font.tables.os2.sTypoAscender);
+ hline('Typo Descender', font.tables.os2.sTypoDescender);
+ }
}
window.redraw = function(options = { withColors: true, withVariations: true }) {
diff --git a/src/encoding.mjs b/src/encoding.mjs
index 0902b8c8..2f7b874c 100644
--- a/src/encoding.mjs
+++ b/src/encoding.mjs
@@ -324,7 +324,7 @@ function addGlyphNamesAll(font) {
glyph = font.glyphs.get(i);
if (font.cffEncoding) {
glyph.name = font.cffEncoding.charset[i];
- } else if (font.glyphNames.names) {
+ } else if (font.glyphNames && font.glyphNames.names) {
glyph.name = font.glyphNames.glyphIndexToName(i);
}
}
diff --git a/src/tables/cmap.mjs b/src/tables/cmap.mjs
index 6193a056..634762db 100644
--- a/src/tables/cmap.mjs
+++ b/src/tables/cmap.mjs
@@ -99,6 +99,19 @@ function parseCmapTableFormat4(cmap, p, data, start, offset) {
}
}
+function parseCmapTableFormat6(cmap, p) {
+ cmap.length = p.parseUShort();
+ cmap.language = p.parseUShort();
+
+ cmap.firstCode = p.parseUShort();
+ cmap.entryCount = p.parseUShort();
+ cmap.glyphIndexMap = {};
+
+ for (let i = 0; i < cmap.entryCount; i += 1) {
+ cmap.glyphIndexMap[cmap.firstCode + i] = p.parseUShort();
+ }
+}
+
function parseCmapTableFormat14(cmap, p) {
const varSelectorList = {};
@@ -216,6 +229,8 @@ function parseCmapTable(data, start) {
parseCmapTableFormat12or13(cmap, p, cmap.format);
} else if (cmap.format === 4) {
parseCmapTableFormat4(cmap, p, data, start, offset);
+ } else if (cmap.format === 6) {
+ parseCmapTableFormat6(cmap, p);
} else {
throw new Error(
'Only format 0 (platformId 1, encodingId 0), 4, 12 and 14 cmap tables are supported ' +
@@ -410,4 +425,4 @@ function makeCmapTable(glyphs) {
export default { parse: parseCmapTable, make: makeCmapTable };
-export { parseCmapTableFormat0, parseCmapTableFormat14 };
+export { parseCmapTableFormat0, parseCmapTableFormat6, parseCmapTableFormat14 };
diff --git a/test/fonts/PDF-Embedded-Calibri-Subset.ttf b/test/fonts/PDF-Embedded-Calibri-Subset.ttf
new file mode 100644
index 00000000..18cae514
Binary files /dev/null and b/test/fonts/PDF-Embedded-Calibri-Subset.ttf differ
diff --git a/test/tables/cmap.spec.mjs b/test/tables/cmap.spec.mjs
index 4ab388a5..574c97f7 100644
--- a/test/tables/cmap.spec.mjs
+++ b/test/tables/cmap.spec.mjs
@@ -1,7 +1,7 @@
import assert from 'assert';
import { unhex } from '../testutil.mjs';
import { Parser } from '../../src/parse.mjs';
-import { parseCmapTableFormat14, parseCmapTableFormat0 } from '../../src/tables/cmap.mjs';
+import { parseCmapTableFormat14, parseCmapTableFormat6, parseCmapTableFormat0 } from '../../src/tables/cmap.mjs';
import { parse } from '../../src/opentype.mjs';
import { readFileSync } from 'fs';
const loadSync = (url, opt) => parse(readFileSync(url), opt);
@@ -82,4 +82,18 @@ describe('tables/cmap.mjs', function() {
const expectedGlyphIds = [1,2,3,4];
assert.deepEqual(glyphIds, expectedGlyphIds);
});
+
+ it('can parse CMAP table format 6', function() {
+ let font;
+ assert.doesNotThrow(function() {
+ font = loadSync('./test/fonts/PDF-Embedded-Calibri-Subset.ttf');
+ });
+
+ // The embedded char IDs for the string "Living Room" in the PDF embedded font
+ const testString = '!"#"$%&\'(()';
+ const glyphIds = font.stringToGlyphIndexes(testString);
+
+ const expectedGlyphIds = [3, 13, 21, 13, 16, 11, 1, 5, 17, 17, 15];
+ assert.deepEqual(glyphIds, expectedGlyphIds);
+ });
});
\ No newline at end of file