makeNameTable function

dynamic makeNameTable(
  1. dynamic names,
  2. dynamic ltag
)

Implementation

makeNameTable(names, ltag) {
    var nameID;
    var nameIDs = [];

    var namesWithNumericKeys = {};
    var nameTableIds = reverseDict(nameTableNames);
    for (var key in names) {
        var id = nameTableIds[key];
        if (id == null) {
            id = key;
        }

        nameID = int.parse(id);

        if (nameID == null) {
            throw('Name table entry "' + key + '" does not exist, see nameTableNames for complete list.');
        }

        namesWithNumericKeys[nameID] = names[key];
        nameIDs.add(nameID);
    }

    var macLanguageIds = reverseDict(macLanguages);
    var windowsLanguageIds = reverseDict(windowsLanguages);

    var nameRecords = [];
    var stringPool = [];

    for (var i = 0; i < nameIDs.length; i++) {
        nameID = nameIDs[i];
        var translations = namesWithNumericKeys[nameID];
        for (var lang in translations) {
            var text = translations[lang];

            // For MacOS, we try to emit the name in the form that was introduced
            // in the initial version of the TrueType spec (in the late 1980s).
            // However, this can fail for various reasons: the requested BCP 47
            // language code might not have an old-style Mac equivalent;
            // we might not have a codec for the needed character encoding;
            // or the name might contain characters that cannot be expressed
            // in the old-style Macintosh encoding. In case of failure, we emit
            // the name in a more modern fashion (Unicode encoding with BCP 47
            // language tags) that is recognized by MacOS 10.5, released in 2009.
            // If fonts were only read by operating systems, we could simply
            // emit all names in the modern form; this would be much easier.
            // However, there are many applications and libraries that read
            // 'name' tables directly, and these will usually only recognize
            // the ancient form (silently skipping the unrecognized names).
            var macPlatform = 1;  // Macintosh
            var macLanguage = macLanguageIds[lang];
            var macScript = macLanguageToScript[macLanguage];
            var macEncoding = getEncoding(macPlatform, macScript, macLanguage);
            var macName = encode_MACSTRING(text, macEncoding);
            if (macName == null) {
                macPlatform = 0;  // Unicode
                macLanguage = ltag.indexOf(lang);
                if (macLanguage < 0) {
                    macLanguage = ltag.length;
                    ltag.push(lang);
                }

                macScript = 4;  // Unicode 2.0 and later
                macName = encode_UTF16(text);
            }

            var macNameOffset = addStringToPool(macName, stringPool);
            nameRecords.add(makeNameRecord(macPlatform, macScript, macLanguage,
                                            nameID, macName.length, macNameOffset));

            var winLanguage = windowsLanguageIds[lang];
            if (winLanguage != null) {
                var winName = encode_UTF16(text);
                var winNameOffset = addStringToPool(winName, stringPool);
                nameRecords.add(makeNameRecord(3, 1, winLanguage,
                                                nameID, winName.length, winNameOffset));
            }
        }
    }

    nameRecords.sort((a, b) {
        return ((a.platformID - b.platformID) ??
                (a.encodingID - b.encodingID) ??
                (a.languageID - b.languageID) ??
                (a.nameID - b.nameID));
    });

    var t = new Table('name', [
        {"name": 'format', "type": 'USHORT', "value": 0},
        {"name": 'count', "type": 'USHORT', "value": nameRecords.length},
        {"name": 'stringOffset', "type": 'USHORT', "value": 6 + nameRecords.length * 12}
    ], null);

    for (var r = 0; r < nameRecords.length; r++) {
        t.fields.push({"name": 'record_${r}', "type": 'RECORD', "value": nameRecords[r]});
    }

    t.fields.push({"name": 'strings', "type": 'LITERAL', "value": stringPool});
    return t;
}