Current File : /home/tradevaly/www/node_modules/fontkit/src/aat/AATFeatureMap.js |
// see https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html
// and /System/Library/Frameworks/CoreText.framework/Versions/A/Headers/SFNTLayoutTypes.h on a Mac
const features = {
allTypographicFeatures: {
code: 0,
exclusive: false,
allTypeFeatures: 0
},
ligatures: {
code: 1,
exclusive: false,
requiredLigatures: 0,
commonLigatures: 2,
rareLigatures: 4,
// logos: 6
rebusPictures: 8,
diphthongLigatures: 10,
squaredLigatures: 12,
abbrevSquaredLigatures: 14,
symbolLigatures: 16,
contextualLigatures: 18,
historicalLigatures: 20
},
cursiveConnection: {
code: 2,
exclusive: true,
unconnected: 0,
partiallyConnected: 1,
cursive: 2
},
letterCase: {
code: 3,
exclusive: true
},
// upperAndLowerCase: 0 # deprecated
// allCaps: 1 # deprecated
// allLowerCase: 2 # deprecated
// smallCaps: 3 # deprecated
// initialCaps: 4 # deprecated
// initialCapsAndSmallCaps: 5 # deprecated
verticalSubstitution: {
code: 4,
exclusive: false,
substituteVerticalForms: 0
},
linguisticRearrangement: {
code: 5,
exclusive: false,
linguisticRearrangement: 0
},
numberSpacing: {
code: 6,
exclusive: true,
monospacedNumbers: 0,
proportionalNumbers: 1,
thirdWidthNumbers: 2,
quarterWidthNumbers: 3
},
smartSwash: {
code: 8,
exclusive: false,
wordInitialSwashes: 0,
wordFinalSwashes: 2,
// lineInitialSwashes: 4
// lineFinalSwashes: 6
nonFinalSwashes: 8
},
diacritics: {
code: 9,
exclusive: true,
showDiacritics: 0,
hideDiacritics: 1,
decomposeDiacritics: 2
},
verticalPosition: {
code: 10,
exclusive: true,
normalPosition: 0,
superiors: 1,
inferiors: 2,
ordinals: 3,
scientificInferiors: 4
},
fractions: {
code: 11,
exclusive: true,
noFractions: 0,
verticalFractions: 1,
diagonalFractions: 2
},
overlappingCharacters: {
code: 13,
exclusive: false,
preventOverlap: 0
},
typographicExtras: {
code: 14,
exclusive: false,
// hyphensToEmDash: 0
// hyphenToEnDash: 2
slashedZero: 4
},
// formInterrobang: 6
// smartQuotes: 8
// periodsToEllipsis: 10
mathematicalExtras: {
code: 15,
exclusive: false,
// hyphenToMinus: 0
// asteristoMultiply: 2
// slashToDivide: 4
// inequalityLigatures: 6
// exponents: 8
mathematicalGreek: 10
},
ornamentSets: {
code: 16,
exclusive: true,
noOrnaments: 0,
dingbats: 1,
piCharacters: 2,
fleurons: 3,
decorativeBorders: 4,
internationalSymbols: 5,
mathSymbols: 6
},
characterAlternatives: {
code: 17,
exclusive: true,
noAlternates: 0
},
// user defined options
designComplexity: {
code: 18,
exclusive: true,
designLevel1: 0,
designLevel2: 1,
designLevel3: 2,
designLevel4: 3,
designLevel5: 4
},
styleOptions: {
code: 19,
exclusive: true,
noStyleOptions: 0,
displayText: 1,
engravedText: 2,
illuminatedCaps: 3,
titlingCaps: 4,
tallCaps: 5
},
characterShape: {
code: 20,
exclusive: true,
traditionalCharacters: 0,
simplifiedCharacters: 1,
JIS1978Characters: 2,
JIS1983Characters: 3,
JIS1990Characters: 4,
traditionalAltOne: 5,
traditionalAltTwo: 6,
traditionalAltThree: 7,
traditionalAltFour: 8,
traditionalAltFive: 9,
expertCharacters: 10,
JIS2004Characters: 11,
hojoCharacters: 12,
NLCCharacters: 13,
traditionalNamesCharacters: 14
},
numberCase: {
code: 21,
exclusive: true,
lowerCaseNumbers: 0,
upperCaseNumbers: 1
},
textSpacing: {
code: 22,
exclusive: true,
proportionalText: 0,
monospacedText: 1,
halfWidthText: 2,
thirdWidthText: 3,
quarterWidthText: 4,
altProportionalText: 5,
altHalfWidthText: 6
},
transliteration: {
code: 23,
exclusive: true,
noTransliteration: 0
},
// hanjaToHangul: 1
// hiraganaToKatakana: 2
// katakanaToHiragana: 3
// kanaToRomanization: 4
// romanizationToHiragana: 5
// romanizationToKatakana: 6
// hanjaToHangulAltOne: 7
// hanjaToHangulAltTwo: 8
// hanjaToHangulAltThree: 9
annotation: {
code: 24,
exclusive: true,
noAnnotation: 0,
boxAnnotation: 1,
roundedBoxAnnotation: 2,
circleAnnotation: 3,
invertedCircleAnnotation: 4,
parenthesisAnnotation: 5,
periodAnnotation: 6,
romanNumeralAnnotation: 7,
diamondAnnotation: 8,
invertedBoxAnnotation: 9,
invertedRoundedBoxAnnotation: 10
},
kanaSpacing: {
code: 25,
exclusive: true,
fullWidthKana: 0,
proportionalKana: 1
},
ideographicSpacing: {
code: 26,
exclusive: true,
fullWidthIdeographs: 0,
proportionalIdeographs: 1,
halfWidthIdeographs: 2
},
unicodeDecomposition: {
code: 27,
exclusive: false,
canonicalComposition: 0,
compatibilityComposition: 2,
transcodingComposition: 4
},
rubyKana: {
code: 28,
exclusive: false,
// noRubyKana: 0 # deprecated - use rubyKanaOff instead
// rubyKana: 1 # deprecated - use rubyKanaOn instead
rubyKana: 2
},
CJKSymbolAlternatives: {
code: 29,
exclusive: true,
noCJKSymbolAlternatives: 0,
CJKSymbolAltOne: 1,
CJKSymbolAltTwo: 2,
CJKSymbolAltThree: 3,
CJKSymbolAltFour: 4,
CJKSymbolAltFive: 5
},
ideographicAlternatives: {
code: 30,
exclusive: true,
noIdeographicAlternatives: 0,
ideographicAltOne: 1,
ideographicAltTwo: 2,
ideographicAltThree: 3,
ideographicAltFour: 4,
ideographicAltFive: 5
},
CJKVerticalRomanPlacement: {
code: 31,
exclusive: true,
CJKVerticalRomanCentered: 0,
CJKVerticalRomanHBaseline: 1
},
italicCJKRoman: {
code: 32,
exclusive: false,
// noCJKItalicRoman: 0 # deprecated - use CJKItalicRomanOff instead
// CJKItalicRoman: 1 # deprecated - use CJKItalicRomanOn instead
CJKItalicRoman: 2
},
caseSensitiveLayout: {
code: 33,
exclusive: false,
caseSensitiveLayout: 0,
caseSensitiveSpacing: 2
},
alternateKana: {
code: 34,
exclusive: false,
alternateHorizKana: 0,
alternateVertKana: 2
},
stylisticAlternatives: {
code: 35,
exclusive: false,
noStylisticAlternates: 0,
stylisticAltOne: 2,
stylisticAltTwo: 4,
stylisticAltThree: 6,
stylisticAltFour: 8,
stylisticAltFive: 10,
stylisticAltSix: 12,
stylisticAltSeven: 14,
stylisticAltEight: 16,
stylisticAltNine: 18,
stylisticAltTen: 20,
stylisticAltEleven: 22,
stylisticAltTwelve: 24,
stylisticAltThirteen: 26,
stylisticAltFourteen: 28,
stylisticAltFifteen: 30,
stylisticAltSixteen: 32,
stylisticAltSeventeen: 34,
stylisticAltEighteen: 36,
stylisticAltNineteen: 38,
stylisticAltTwenty: 40
},
contextualAlternates: {
code: 36,
exclusive: false,
contextualAlternates: 0,
swashAlternates: 2,
contextualSwashAlternates: 4
},
lowerCase: {
code: 37,
exclusive: true,
defaultLowerCase: 0,
lowerCaseSmallCaps: 1,
lowerCasePetiteCaps: 2
},
upperCase: {
code: 38,
exclusive: true,
defaultUpperCase: 0,
upperCaseSmallCaps: 1,
upperCasePetiteCaps: 2
},
languageTag: { // indices into ltag table
code: 39,
exclusive: true
},
CJKRomanSpacing: {
code: 103,
exclusive: true,
halfWidthCJKRoman: 0,
proportionalCJKRoman: 1,
defaultCJKRoman: 2,
fullWidthCJKRoman: 3
}
};
const feature = (name, selector) => [features[name].code, features[name][selector]];
const OTMapping = {
rlig: feature('ligatures', 'requiredLigatures'),
clig: feature('ligatures', 'contextualLigatures'),
dlig: feature('ligatures', 'rareLigatures'),
hlig: feature('ligatures', 'historicalLigatures'),
liga: feature('ligatures', 'commonLigatures'),
hist: feature('ligatures', 'historicalLigatures'), // ??
smcp: feature('lowerCase', 'lowerCaseSmallCaps'),
pcap: feature('lowerCase', 'lowerCasePetiteCaps'),
frac: feature('fractions', 'diagonalFractions'),
dnom: feature('fractions', 'diagonalFractions'), // ??
numr: feature('fractions', 'diagonalFractions'), // ??
afrc: feature('fractions', 'verticalFractions'),
// aalt
// abvf, abvm, abvs, akhn, blwf, blwm, blws, cfar, cjct, cpsp, falt, isol, jalt, ljmo, mset?
// ltra, ltrm, nukt, pref, pres, pstf, psts, rand, rkrf, rphf, rtla, rtlm, size, tjmo, tnum?
// unic, vatu, vhal, vjmo, vpal, vrt2
// dist -> trak table?
// kern, vkrn -> kern table
// lfbd + opbd + rtbd -> opbd table?
// mark, mkmk -> acnt table?
// locl -> languageTag + ltag table
case: feature('caseSensitiveLayout', 'caseSensitiveLayout'), // also caseSensitiveSpacing
ccmp: feature('unicodeDecomposition', 'canonicalComposition'), // compatibilityComposition?
cpct: feature('CJKVerticalRomanPlacement', 'CJKVerticalRomanCentered'), // guess..., probably not given below
valt: feature('CJKVerticalRomanPlacement', 'CJKVerticalRomanCentered'),
swsh: feature('contextualAlternates', 'swashAlternates'),
cswh: feature('contextualAlternates', 'contextualSwashAlternates'),
curs: feature('cursiveConnection', 'cursive'), // ??
c2pc: feature('upperCase', 'upperCasePetiteCaps'),
c2sc: feature('upperCase', 'upperCaseSmallCaps'),
init: feature('smartSwash', 'wordInitialSwashes'), // ??
fin2: feature('smartSwash', 'wordFinalSwashes'), // ??
medi: feature('smartSwash', 'nonFinalSwashes'), // ??
med2: feature('smartSwash', 'nonFinalSwashes'), // ??
fin3: feature('smartSwash', 'wordFinalSwashes'), // ??
fina: feature('smartSwash', 'wordFinalSwashes'), // ??
pkna: feature('kanaSpacing', 'proportionalKana'),
half: feature('textSpacing', 'halfWidthText'), // also HalfWidthCJKRoman, HalfWidthIdeographs?
halt: feature('textSpacing', 'altHalfWidthText'),
hkna: feature('alternateKana', 'alternateHorizKana'),
vkna: feature('alternateKana', 'alternateVertKana'),
// hngl: feature 'transliteration', 'hanjaToHangulSelector' # deprecated
ital: feature('italicCJKRoman', 'CJKItalicRoman'),
lnum: feature('numberCase', 'upperCaseNumbers'),
onum: feature('numberCase', 'lowerCaseNumbers'),
mgrk: feature('mathematicalExtras', 'mathematicalGreek'),
// nalt: not enough info. what type of annotation?
// ornm: ditto, which ornament style?
calt: feature('contextualAlternates', 'contextualAlternates'), // or more?
vrt2: feature('verticalSubstitution', 'substituteVerticalForms'), // oh... below?
vert: feature('verticalSubstitution', 'substituteVerticalForms'),
tnum: feature('numberSpacing', 'monospacedNumbers'),
pnum: feature('numberSpacing', 'proportionalNumbers'),
sups: feature('verticalPosition', 'superiors'),
subs: feature('verticalPosition', 'inferiors'),
ordn: feature('verticalPosition', 'ordinals'),
pwid: feature('textSpacing', 'proportionalText'),
hwid: feature('textSpacing', 'halfWidthText'),
qwid: feature('textSpacing', 'quarterWidthText'), // also QuarterWidthNumbers?
twid: feature('textSpacing', 'thirdWidthText'), // also ThirdWidthNumbers?
fwid: feature('textSpacing', 'proportionalText'), //??
palt: feature('textSpacing', 'altProportionalText'),
trad: feature('characterShape', 'traditionalCharacters'),
smpl: feature('characterShape', 'simplifiedCharacters'),
jp78: feature('characterShape', 'JIS1978Characters'),
jp83: feature('characterShape', 'JIS1983Characters'),
jp90: feature('characterShape', 'JIS1990Characters'),
jp04: feature('characterShape', 'JIS2004Characters'),
expt: feature('characterShape', 'expertCharacters'),
hojo: feature('characterShape', 'hojoCharacters'),
nlck: feature('characterShape', 'NLCCharacters'),
tnam: feature('characterShape', 'traditionalNamesCharacters'),
ruby: feature('rubyKana', 'rubyKana'),
titl: feature('styleOptions', 'titlingCaps'),
zero: feature('typographicExtras', 'slashedZero'),
ss01: feature('stylisticAlternatives', 'stylisticAltOne'),
ss02: feature('stylisticAlternatives', 'stylisticAltTwo'),
ss03: feature('stylisticAlternatives', 'stylisticAltThree'),
ss04: feature('stylisticAlternatives', 'stylisticAltFour'),
ss05: feature('stylisticAlternatives', 'stylisticAltFive'),
ss06: feature('stylisticAlternatives', 'stylisticAltSix'),
ss07: feature('stylisticAlternatives', 'stylisticAltSeven'),
ss08: feature('stylisticAlternatives', 'stylisticAltEight'),
ss09: feature('stylisticAlternatives', 'stylisticAltNine'),
ss10: feature('stylisticAlternatives', 'stylisticAltTen'),
ss11: feature('stylisticAlternatives', 'stylisticAltEleven'),
ss12: feature('stylisticAlternatives', 'stylisticAltTwelve'),
ss13: feature('stylisticAlternatives', 'stylisticAltThirteen'),
ss14: feature('stylisticAlternatives', 'stylisticAltFourteen'),
ss15: feature('stylisticAlternatives', 'stylisticAltFifteen'),
ss16: feature('stylisticAlternatives', 'stylisticAltSixteen'),
ss17: feature('stylisticAlternatives', 'stylisticAltSeventeen'),
ss18: feature('stylisticAlternatives', 'stylisticAltEighteen'),
ss19: feature('stylisticAlternatives', 'stylisticAltNineteen'),
ss20: feature('stylisticAlternatives', 'stylisticAltTwenty')
};
// salt: feature 'stylisticAlternatives', 'stylisticAltOne' # hmm, which one to choose
// Add cv01-cv99 features
for (let i = 1; i <= 99; i++) {
OTMapping[`cv${`00${i}`.slice(-2)}`] = [features.characterAlternatives.code, i];
}
// create inverse mapping
let AATMapping = {};
for (let ot in OTMapping) {
let aat = OTMapping[ot];
if (AATMapping[aat[0]] == null) {
AATMapping[aat[0]] = {};
}
AATMapping[aat[0]][aat[1]] = ot;
}
// Maps an array of OpenType features to AAT features
// in the form of {featureType:{featureSetting:true}}
export function mapOTToAAT(features) {
let res = {};
for (let k in features) {
let r;
if (r = OTMapping[k]) {
if (res[r[0]] == null) {
res[r[0]] = {};
}
res[r[0]][r[1]] = features[k];
}
}
return res;
}
// Maps strings in a [featureType, featureSetting]
// to their equivalent number codes
function mapFeatureStrings(f) {
let [type, setting] = f;
if (isNaN(type)) {
var typeCode = features[type] && features[type].code;
} else {
var typeCode = type;
}
if (isNaN(setting)) {
var settingCode = features[type] && features[type][setting];
} else {
var settingCode = setting;
}
return [typeCode, settingCode];
}
// Maps AAT features to an array of OpenType features
// Supports both arrays in the form of [[featureType, featureSetting]]
// and objects in the form of {featureType:{featureSetting:true}}
// featureTypes and featureSettings can be either strings or number codes
export function mapAATToOT(features) {
let res = {};
if (Array.isArray(features)) {
for (let k = 0; k < features.length; k++) {
let r;
let f = mapFeatureStrings(features[k]);
if (r = AATMapping[f[0]] && AATMapping[f[0]][f[1]]) {
res[r] = true;
}
}
} else if (typeof features === 'object') {
for (let type in features) {
let feature = features[type];
for (let setting in feature) {
let r;
let f = mapFeatureStrings([type, setting]);
if (feature[setting] && (r = AATMapping[f[0]] && AATMapping[f[0]][f[1]])) {
res[r] = true;
}
}
}
}
return Object.keys(res);
}