315 lines
8.5 KiB
C
315 lines
8.5 KiB
C
// 14 february 2017
|
|
#include "../ui.h"
|
|
#include "uipriv.h"
|
|
|
|
// Notes:
|
|
// - Each tag should only appear in quotes once (including within comments); this allows automated tools to determine what we cover and don't cover
|
|
|
|
static void boolspec(uiAttributeSpec *spec, const char *featureTag, specToOpenTypeEnumFunc f, void *data)
|
|
{
|
|
if (spec->Value != 0) {
|
|
(*f)(featureTag, 1, data);
|
|
return;
|
|
}
|
|
(*f)(featureTag, 0, data);
|
|
}
|
|
|
|
static void boolspecnot(uiAttributeSpec *spec, const char *featureTag, specToOpenTypeEnumFunc f, void *data)
|
|
{
|
|
if (spec->Value == 0) {
|
|
(*f)(featureTag, 1, data);
|
|
return;
|
|
}
|
|
(*f)(featureTag, 0, data);
|
|
}
|
|
|
|
void specToOpenType(uiAttributeSpec *spec, specToOpenTypeEnumFunc f, void *data)
|
|
{
|
|
switch (spec->Type) {
|
|
case uiAttributeStandardLigatures:
|
|
boolspec(spec, "liga", f, data);
|
|
return;
|
|
case uiAttributeRequiredLigatures:
|
|
boolspec(spec, "rlig", f, data);
|
|
return;
|
|
case uiAttributeDiscretionaryLigatures:
|
|
boolspec(spec, "dlig", f, data);
|
|
return;
|
|
case uiAttributeContextualLigatures:
|
|
boolspec(spec, "clig", f, data);
|
|
return;
|
|
case uiAttributeHistoricalLigatures:
|
|
boolspec(spec, "hlig", f, data);
|
|
// This technically isn't what is meant by "historical ligatures", but Core Text's internal AAT-to-OpenType mapping says to include it, so we include it too
|
|
boolspec(spec, "hist", f, data);
|
|
return;
|
|
case uiAttributeUnicase:
|
|
boolspec(spec, "unic", f, data);
|
|
return;
|
|
// TODO is this correct or should we explicitly switch the rest off too?
|
|
case uiAttributeNumberSpacings:
|
|
// TODO does Core Text set both? do we?
|
|
switch (spec->Value) {
|
|
case uiAttributeNumberSpacingProportional:
|
|
(*f)("pnum", 1, data);
|
|
break;
|
|
case uiAttributeNumberSpacingTabular:
|
|
(*f)("tnum", 1, data);
|
|
break;
|
|
}
|
|
return;
|
|
case uiAttributeSuperscripts:
|
|
switch (spec->Value) {
|
|
case uiAttributeSuperscriptSuperscript:
|
|
(*f)("sups", 1, data);
|
|
break;
|
|
case uiAttributeSuperscriptSubscript:
|
|
(*f)("subs", 1, data);
|
|
break;
|
|
case uiAttributeSuperscriptOrdinal:
|
|
(*f)("ordn", 1, data);
|
|
break;
|
|
case uiAttributeSuperscriptScientificInferior:
|
|
(*f)("sinf", 1, data);
|
|
break;
|
|
}
|
|
return;
|
|
// TODO is this correct or should we explicitly switch the rest off too?
|
|
case uiAttributeFractionForms:
|
|
switch (spec->Value) {
|
|
case uiAttributeFractionFormVertical:
|
|
(*f)("afrc", 1, data);
|
|
break;
|
|
case uiAttributeFractionFormDiagonal:
|
|
(*f)("frac", 1, data);
|
|
break;
|
|
}
|
|
return;
|
|
case uiAttributeSlashedZero:
|
|
boolspec(spec, "zero", f, data);
|
|
return;
|
|
case uiAttributeMathematicalGreek:
|
|
boolspec(spec, "mgrk", f, data);
|
|
return;
|
|
case uiAttributeOrnamentalForms:
|
|
(*f)("ornm", (uint32_t) (spec->Value), data);
|
|
return;
|
|
case uiAttributeSpecificCharacterForm:
|
|
(*f)("aalt", (uint32_t) (spec->Value), data);
|
|
return;
|
|
case uiAttributeTitlingCapitalForms:
|
|
boolspec(spec, "titl", f, data);
|
|
return;
|
|
// TODO is this correct or should we explicitly switch the rest off too?
|
|
case uiAttributeHanCharacterForms:
|
|
switch (spec->Value) {
|
|
case uiAttributeHanCharacterFormTraditional:
|
|
(*f)("trad", 1, data);
|
|
break;
|
|
case uiAttributeHanCharacterFormSimplified:
|
|
(*f)("smpl", 1, data);
|
|
break;
|
|
case uiAttributeHanCharacterFormJIS1978:
|
|
(*f)("jp78", 1, data);
|
|
break;
|
|
case uiAttributeHanCharacterFormJIS1983:
|
|
(*f)("jp83", 1, data);
|
|
break;
|
|
case uiAttributeHanCharacterFormJIS1990:
|
|
(*f)("jp90", 1, data);
|
|
break;
|
|
case uiAttributeHanCharacterFormExpert:
|
|
(*f)("expt", 1, data);
|
|
break;
|
|
case uiAttributeHanCharacterFormJIS2004:
|
|
(*f)("jp04", 1, data);
|
|
break;
|
|
case uiAttributeHanCharacterFormHojo:
|
|
(*f)("hojo", 1, data);
|
|
break;
|
|
case uiAttributeHanCharacterFormNLC:
|
|
(*f)("nlck", 1, data);
|
|
break;
|
|
case uiAttributeHanCharacterFormTraditionalNames:
|
|
(*f)("tnam", 1, data);
|
|
break;
|
|
}
|
|
return;
|
|
case uiAttributeLowercaseNumbers:
|
|
boolspec(spec, "onum", f, data);
|
|
// Core Text's internal AAT-to-OpenType mapping says to include this, so we include it too
|
|
// TODO is it always set?
|
|
boolspecnot(spec, "lnum", f, data);
|
|
return;
|
|
case uiAttributeHanjaToHangul:
|
|
boolspec(spec, "hngl", f, data);
|
|
return;
|
|
case uiAttributeAnnotatedGlyphForms:
|
|
(*f)("nalt", (uint32_t) (spec->Value), data);
|
|
return;
|
|
case uiAttributeRubyKanaForms:
|
|
boolspec(spec, "ruby", f, data);
|
|
return;
|
|
case uiAttributeCJKRomansToItalics:
|
|
boolspec(spec, "ital", f, data);
|
|
return;
|
|
case uiAttributeCaseSensitiveForms:
|
|
boolspec(spec, "case", f, data);
|
|
return;
|
|
case uiAttributeCapitalSpacing:
|
|
boolspec(spec, "cpsp", f, data);
|
|
return;
|
|
case uiAttributeAlternateHorizontalKana:
|
|
boolspec(spec, "hkna", f, data);
|
|
return;
|
|
case uiAttributeAlternateVerticalKana:
|
|
boolspec(spec, "vkna", f, data);
|
|
return;
|
|
case uiAttributeStylisticAlternate1:
|
|
boolspec(spec, "ss01", f, data);
|
|
return;
|
|
case uiAttributeStylisticAlternate2:
|
|
boolspec(spec, "ss02", f, data);
|
|
return;
|
|
case uiAttributeStylisticAlternate3:
|
|
boolspec(spec, "ss03", f, data);
|
|
return;
|
|
case uiAttributeStylisticAlternate4:
|
|
boolspec(spec, "ss04", f, data);
|
|
return;
|
|
case uiAttributeStylisticAlternate5:
|
|
boolspec(spec, "ss05", f, data);
|
|
return;
|
|
case uiAttributeStylisticAlternate6:
|
|
boolspec(spec, "ss06", f, data);
|
|
return;
|
|
case uiAttributeStylisticAlternate7:
|
|
boolspec(spec, "ss07", f, data);
|
|
return;
|
|
case uiAttributeStylisticAlternate8:
|
|
boolspec(spec, "ss08", f, data);
|
|
return;
|
|
case uiAttributeStylisticAlternate9:
|
|
boolspec(spec, "ss09", f, data);
|
|
return;
|
|
case uiAttributeStylisticAlternate10:
|
|
boolspec(spec, "ss10", f, data);
|
|
return;
|
|
case uiAttributeStylisticAlternate11:
|
|
boolspec(spec, "ss11", f, data);
|
|
return;
|
|
case uiAttributeStylisticAlternate12:
|
|
boolspec(spec, "ss12", f, data);
|
|
return;
|
|
case uiAttributeStylisticAlternate13:
|
|
boolspec(spec, "ss13", f, data);
|
|
return;
|
|
case uiAttributeStylisticAlternate14:
|
|
boolspec(spec, "ss14", f, data);
|
|
return;
|
|
case uiAttributeStylisticAlternate15:
|
|
boolspec(spec, "ss15", f, data);
|
|
return;
|
|
case uiAttributeStylisticAlternate16:
|
|
boolspec(spec, "ss16", f, data);
|
|
return;
|
|
case uiAttributeStylisticAlternate17:
|
|
boolspec(spec, "ss17", f, data);
|
|
return;
|
|
case uiAttributeStylisticAlternate18:
|
|
boolspec(spec, "ss18", f, data);
|
|
return;
|
|
case uiAttributeStylisticAlternate19:
|
|
boolspec(spec, "ss19", f, data);
|
|
return;
|
|
case uiAttributeStylisticAlternate20:
|
|
boolspec(spec, "ss20", f, data);
|
|
return;
|
|
case uiAttributeContextualAlternates:
|
|
boolspec(spec, "calt", f, data);
|
|
return;
|
|
case uiAttributeSwashes:
|
|
boolspec(spec, "swsh", f, data);
|
|
return;
|
|
case uiAttributeContextualSwashes:
|
|
boolspec(spec, "cswh", f, data);
|
|
return;
|
|
// TODO is this correct or should we explicitly switch the rest off too?
|
|
case uiAttributeLowercaseCapForms:
|
|
switch (spec->Value) {
|
|
case uiAttributeCapFormSmallCaps:
|
|
(*f)("smcp", 1, data);
|
|
break;
|
|
case uiAttributeCapFormPetiteCaps:
|
|
(*f)("pcap", 1, data);
|
|
break;
|
|
}
|
|
return;
|
|
// TODO is this correct or should we explicitly switch the rest off too?
|
|
case uiAttributeUppercaseCapForms:
|
|
switch (spec->Value) {
|
|
case uiAttributeCapFormSmallCaps:
|
|
(*f)("c2sc", 1, data);
|
|
break;
|
|
case uiAttributeCapFormPetiteCaps:
|
|
(*f)("c2pc", 1, data);
|
|
break;
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
// TODO missing that AAT uses directly:
|
|
// - pkna, pwid, fwid, hwid, twid, qwid, palt, valt, vpal, halt, vhal, kern, vkrn (CJK width control)
|
|
// missing that AAT knows about:
|
|
// - ccmp (compositions)
|
|
// - dnom, numr (fraction parts) — no AAT equivalent...
|
|
// - falt, jalt (Arabic support)
|
|
// - rclt (required contextual alternates)
|
|
// - lfbd, opbd, rtbd (optical bounds support)
|
|
// - locl (Cyrillic support)
|
|
// - ltra, ltrm, rtla, rtlm (bidi support)
|
|
// - mark, mkmk (mark positioning)
|
|
// - rand (random glyph selection candidates)
|
|
// - salt (stylistic alternatives)
|
|
// - size (sizing info)
|
|
//
|
|
// script-specific; core text and pango/harfbuzz use these automatically based on the language
|
|
// TODO if DirectWrite does too we can ignore them and just provide a language attribute (they all use BCP 47 syntax for language names)
|
|
// Tag Core Text? Harfbuzz?
|
|
// abvf yes yes
|
|
// abvm yes yes
|
|
// abvs yes TODO
|
|
// akhn yes yes
|
|
// blwf yes yes
|
|
// blwm yes yes
|
|
// blws yes TODO
|
|
// cjct yes yes
|
|
// curs yes yes
|
|
// dist yes yes
|
|
// falt TODO TODO
|
|
// fin2 yes yes
|
|
// fin3 yes yes
|
|
// fina yes yes
|
|
// half yes yes
|
|
// haln yes yes
|
|
// init yes yes
|
|
// isol yes yes
|
|
// jalt TODO TODO
|
|
// ljmo yes yes
|
|
// locl TODO all horz(!)
|
|
// med2 yes yes
|
|
// medi yes yes
|
|
// mset TODO yes
|
|
// nukt yes yes
|
|
// pref yes yes
|
|
// pres yes yes
|
|
// pstf yes yes
|
|
// psts yes yes
|
|
// rclt TODO all horz(!)
|
|
// rkrf yes yes
|
|
// rphf yes yes
|
|
// tjmo yes yes
|
|
// vatu yes yes
|
|
// vjmo yes yes
|