Skip to content

Commit

Permalink
handle CMAP format 0 for platform 1, encoding 0 (legacy Macintosh enc…
Browse files Browse the repository at this point in the history
…oding)
  • Loading branch information
Connum committed Nov 5, 2023
1 parent 9266555 commit 7d3486c
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 9 deletions.
40 changes: 34 additions & 6 deletions src/tables/cmap.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,25 @@
import check from '../check.js';
import parse from '../parse.js';
import table from '../table.js';
import { eightBitMacEncodings } from '../types.js';
import { getEncoding } from '../tables/name.js';

function parseCmapTableFormat0(cmap, p, platformID, encodingID) {
// Length in bytes of the index map
cmap.length = p.parseUShort();
// see https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6name.html
// section "Macintosh Language Codes"
cmap.language = p.parseUShort() - 1;

const indexMap = p.parseByteList(cmap.length);
const glyphIndexMap = Object.assign({}, indexMap);
const encoding = getEncoding(platformID, encodingID, cmap.language);
const decodingTable = eightBitMacEncodings[encoding];
for (let i = 0; i < decodingTable.length; i++) {
glyphIndexMap[decodingTable.charCodeAt(i)] = indexMap[0x80 + i];
}
cmap.glyphIndexMap = glyphIndexMap;
}

function parseCmapTableFormat12(cmap, p) {
//Skip reserved.
Expand Down Expand Up @@ -150,11 +169,15 @@ function parseCmapTable(data, start) {
let format14Parser = null;
let format14offset = -1;
let offset = -1;
let platformId = null;
let encodingId = null;
for (let i = cmap.numTables - 1; i >= 0; i -= 1) {
const platformId = parse.getUShort(data, start + 4 + (i * 8));
const encodingId = parse.getUShort(data, start + 4 + (i * 8) + 2);
platformId = parse.getUShort(data, start + 4 + (i * 8));
encodingId = parse.getUShort(data, start + 4 + (i * 8) + 2);
if ((platformId === 3 && (encodingId === 0 || encodingId === 1 || encodingId === 10)) ||
(platformId === 0 && (encodingId === 0 || encodingId === 1 || encodingId === 2 || encodingId === 3 || encodingId === 4))) {
(platformId === 0 && (encodingId === 0 || encodingId === 1 || encodingId === 2 || encodingId === 3 || encodingId === 4)) ||
(platformId === 1 && encodingId === 0) // MacOS <= 9
) {
offset = parse.getULong(data, start + 4 + (i * 8) + 4);
// allow for early break
if (format14Parser) {
Expand All @@ -178,12 +201,17 @@ function parseCmapTable(data, start) {
const p = new parse.Parser(data, start + offset);
cmap.format = p.parseUShort();

if (cmap.format === 12) {
if (cmap.format === 0) {
parseCmapTableFormat0(cmap, p, platformId, encodingId);
} else if (cmap.format === 12) {
parseCmapTableFormat12(cmap, p);
} else if (cmap.format === 4) {
parseCmapTableFormat4(cmap, p, data, start, offset);
} else {
throw new Error('Only format 4, 12 and 14 cmap tables are supported (found format ' + cmap.format + ').');
throw new Error(
'Only format 0 (platformId 1, encodingId 0), 4, 12 and 14 cmap tables are supported ' +
'(found format ' + cmap.format + ', platformId ' + platformId + ', encodingId ' + encodingId + ').'
);
}

// format 14 is the only one that's not exclusive but can be used as a supplement.
Expand Down Expand Up @@ -361,4 +389,4 @@ function makeCmapTable(glyphs) {

export default { parse: parseCmapTable, make: makeCmapTable };

export { parseCmapTableFormat14 };
export { parseCmapTableFormat0, parseCmapTableFormat14 };
2 changes: 1 addition & 1 deletion src/tables/name.js
Original file line number Diff line number Diff line change
Expand Up @@ -604,7 +604,7 @@ const macLanguageEncodings = {
146: 'x-mac-gaelic' // langIrishGaelicScript
};

function getEncoding(platformID, encodingID, languageID) {
export function getEncoding(platformID, encodingID, languageID) {
switch (platformID) {
case 0: // Unicode
return utf16;
Expand Down
2 changes: 1 addition & 1 deletion src/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -437,7 +437,7 @@ sizeOf.UTF16 = function(v) {
/**
* @private
*/
const eightBitMacEncodings = {
export const eightBitMacEncodings = {
'x-mac-croatian': // Python: 'mac_croatian'
'ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶ß®Š™´¨≠ŽØ∞±≤≥∆µ∂∑∏š∫ªºΩžø' +
'¿¡¬√ƒ≈Ć«Č… ÀÃÕŒœĐ—“”‘’÷◊©⁄€‹›Æ»–·‚„‰ÂćÁčÈÍÎÏÌÓÔđÒÚÛÙıˆ˜¯πË˚¸Êæˇ',
Expand Down
5 changes: 5 additions & 0 deletions test/fonts/LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ TestCMAP14.otf
http://www.apache.org/licenses/LICENSE-2.0
https://github.com/unicode-org/text-rendering-tests/blob/main/LICENSE.md

TestCMAPMacTurkish.ttf
Copyright © 2016 by Unicode Inc.
SIL Open Font License, Version 1.1
https://opensource.org/licenses/OFL-1.1

Vibur.woff
Copyright (c) 2010, Johan Kallas ([email protected]).
SIL Open Font License, Version 1.1
Expand Down
Binary file added test/fonts/TestCMAPMacTurkish.ttf
Binary file not shown.
18 changes: 17 additions & 1 deletion test/tables/cmap.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import assert from 'assert';
import { unhex } from '../testutil';
import { Parser } from '../../src/parse';
import { parseCmapTableFormat14 } from '../../src/tables/cmap';
import { parseCmapTableFormat14, parseCmapTableFormat0 } from '../../src/tables/cmap';
import { parse } from '../../src/opentype.js';
import { readFileSync } from 'fs';
const loadSync = (url, opt) => parse(readFileSync(url), opt);

describe('tables/cmap.js', function() {

Expand Down Expand Up @@ -55,4 +58,17 @@ describe('tables/cmap.js', function() {
assert.deepEqual(cmap.varSelectorList, expectedData);
});

it('can parse CMAP format 0 legacy Mac encoding', function() {
let font;
assert.doesNotThrow(function() {
font = loadSync('./test/fonts/TestCMAPMacTurkish.ttf');
});
const testString = '“ABÇĞIİÖŞÜ”abçğıiöşüă';
const glyphIds = [];
const expectedGlyphIds = [200,34,35,126,176,42,178,140,181,145,201,66,67,154,177,222,74,168,182,174,123,184];
for (let i = 0; i < testString.length; i++) {
glyphIds.push(font.charToGlyphIndex(testString.charAt(i)));
}
assert.deepEqual(glyphIds, expectedGlyphIds);
});
});

0 comments on commit 7d3486c

Please sign in to comment.