2017-02-14 18:00:35 -06:00
// 14 february 2017
# include "../ui.h"
# include "uipriv.h"
2017-02-14 20:18:56 -06:00
// Notes:
2017-02-14 21:37:01 -06:00
// - Each tag should only appear in quotes once (including within comments); this allows automated tools to determine what we cover and don't cover
2017-02-14 18:00:35 -06:00
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 ) ;
}
2017-02-14 20:18:56 -06:00
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 ) ;
}
2017-02-14 18:00:35 -06:00
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 ) ;
2017-02-14 20:18:56 -06:00
// 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 ) ;
2017-02-14 18:00:35 -06:00
return ;
case uiAttributeUnicase :
boolspec ( spec , " unic " , f , data ) ;
return ;
// TODO is this correct or should we explicitly switch the rest off too?
2017-02-14 20:18:56 -06:00
case uiAttributeNumberSpacings :
// TODO does Core Text set both? do we?
switch ( spec - > Value ) {
case uiAttributeNumberSpacingProportional :
( * f ) ( " pnum " , 1 , data ) ;
break ;
2017-02-15 22:10:23 -06:00
case uiAttributeNumberSpacingTabular :
2017-02-14 20:18:56 -06:00
( * f ) ( " tnum " , 1 , data ) ;
break ;
}
return ;
2017-02-14 18:00:35 -06:00
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 :
2017-02-20 13:59:43 -06:00
boolspec ( spec , " zero " , f , data ) ;
2017-02-14 18:00:35 -06:00
return ;
case uiAttributeMathematicalGreek :
2017-02-20 13:59:43 -06:00
boolspec ( spec , " mgrk " , f , data ) ;
2017-02-14 18:00:35 -06:00
return ;
case uiAttributeOrnamentalForms :
( * f ) ( " ornm " , ( uint32_t ) ( spec - > Value ) , data ) ;
return ;
2017-02-14 20:18:56 -06:00
case uiAttributeSpecificCharacterForm :
( * f ) ( " aalt " , ( uint32_t ) ( spec - > Value ) , data ) ;
return ;
2017-02-14 18:00:35 -06:00
case uiAttributeTitlingCapitalForms :
2017-02-20 13:59:43 -06:00
boolspec ( spec , " titl " , f , data ) ;
2017-02-14 18:00:35 -06:00
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 :
2017-02-20 13:59:43 -06:00
boolspec ( spec , " onum " , f , data ) ;
2017-02-14 20:18:56 -06:00
// Core Text's internal AAT-to-OpenType mapping says to include this, so we include it too
// TODO is it always set?
2017-02-20 13:59:43 -06:00
boolspecnot ( spec , " lnum " , f , data ) ;
2017-02-14 20:18:56 -06:00
return ;
case uiAttributeHanjaToHangul :
2017-02-20 13:59:43 -06:00
boolspec ( spec , " hngl " , f , data ) ;
2017-02-14 18:00:35 -06:00
return ;
2017-02-24 17:15:20 -06:00
case uiAttributeAnnotatedGlyphForms :
2017-02-14 18:00:35 -06:00
( * f ) ( " nalt " , ( uint32_t ) ( spec - > Value ) , data ) ;
return ;
2017-02-15 00:34:26 -06:00
case uiAttributeRubyKanaForms :
2017-02-20 13:59:43 -06:00
boolspec ( spec , " ruby " , f , data ) ;
2017-02-15 00:34:26 -06:00
return ;
2017-02-15 22:10:23 -06:00
case uiAttributeCJKRomansToItalics :
2017-02-20 13:59:43 -06:00
boolspec ( spec , " ital " , f , data ) ;
2017-02-14 18:00:35 -06:00
return ;
case uiAttributeCaseSensitiveForms :
2017-02-20 13:59:43 -06:00
boolspec ( spec , " case " , f , data ) ;
2017-02-14 18:00:35 -06:00
return ;
case uiAttributeCapitalSpacing :
2017-02-20 13:59:43 -06:00
boolspec ( spec , " cpsp " , f , data ) ;
2017-02-14 18:00:35 -06:00
return ;
case uiAttributeAlternateHorizontalKana :
2017-02-20 13:59:43 -06:00
boolspec ( spec , " hkna " , f , data ) ;
2017-02-14 18:00:35 -06:00
return ;
case uiAttributeAlternateVerticalKana :
2017-02-20 13:59:43 -06:00
boolspec ( spec , " vkna " , f , data ) ;
2017-02-14 18:00:35 -06:00
return ;
2017-02-24 17:19:34 -06:00
case uiAttributeStylisticAlternate1 :
2017-02-20 13:59:43 -06:00
boolspec ( spec , " ss01 " , f , data ) ;
2017-02-14 18:00:35 -06:00
return ;
2017-02-24 17:19:34 -06:00
case uiAttributeStylisticAlternate2 :
2017-02-20 13:59:43 -06:00
boolspec ( spec , " ss02 " , f , data ) ;
2017-02-14 18:00:35 -06:00
return ;
2017-02-24 17:19:34 -06:00
case uiAttributeStylisticAlternate3 :
2017-02-20 13:59:43 -06:00
boolspec ( spec , " ss03 " , f , data ) ;
2017-02-14 18:00:35 -06:00
return ;
2017-02-24 17:19:34 -06:00
case uiAttributeStylisticAlternate4 :
2017-02-20 13:59:43 -06:00
boolspec ( spec , " ss04 " , f , data ) ;
2017-02-14 18:00:35 -06:00
return ;
2017-02-24 17:19:34 -06:00
case uiAttributeStylisticAlternate5 :
2017-02-20 13:59:43 -06:00
boolspec ( spec , " ss05 " , f , data ) ;
2017-02-14 18:00:35 -06:00
return ;
2017-02-24 17:19:34 -06:00
case uiAttributeStylisticAlternate6 :
2017-02-20 13:59:43 -06:00
boolspec ( spec , " ss06 " , f , data ) ;
2017-02-14 18:00:35 -06:00
return ;
2017-02-24 17:19:34 -06:00
case uiAttributeStylisticAlternate7 :
2017-02-20 13:59:43 -06:00
boolspec ( spec , " ss07 " , f , data ) ;
2017-02-14 18:00:35 -06:00
return ;
2017-02-24 17:19:34 -06:00
case uiAttributeStylisticAlternate8 :
2017-02-20 13:59:43 -06:00
boolspec ( spec , " ss08 " , f , data ) ;
2017-02-14 18:00:35 -06:00
return ;
2017-02-24 17:19:34 -06:00
case uiAttributeStylisticAlternate9 :
2017-02-20 13:59:43 -06:00
boolspec ( spec , " ss09 " , f , data ) ;
2017-02-14 18:00:35 -06:00
return ;
2017-02-24 17:19:34 -06:00
case uiAttributeStylisticAlternate10 :
2017-02-20 13:59:43 -06:00
boolspec ( spec , " ss10 " , f , data ) ;
2017-02-14 18:00:35 -06:00
return ;
2017-02-24 17:19:34 -06:00
case uiAttributeStylisticAlternate11 :
2017-02-20 13:59:43 -06:00
boolspec ( spec , " ss11 " , f , data ) ;
2017-02-14 18:00:35 -06:00
return ;
2017-02-24 17:19:34 -06:00
case uiAttributeStylisticAlternate12 :
2017-02-20 13:59:43 -06:00
boolspec ( spec , " ss12 " , f , data ) ;
2017-02-14 18:00:35 -06:00
return ;
2017-02-24 17:19:34 -06:00
case uiAttributeStylisticAlternate13 :
2017-02-20 13:59:43 -06:00
boolspec ( spec , " ss13 " , f , data ) ;
2017-02-14 18:00:35 -06:00
return ;
2017-02-24 17:19:34 -06:00
case uiAttributeStylisticAlternate14 :
2017-02-20 13:59:43 -06:00
boolspec ( spec , " ss14 " , f , data ) ;
2017-02-14 18:00:35 -06:00
return ;
2017-02-24 17:19:34 -06:00
case uiAttributeStylisticAlternate15 :
2017-02-20 13:59:43 -06:00
boolspec ( spec , " ss15 " , f , data ) ;
2017-02-14 18:00:35 -06:00
return ;
2017-02-24 17:19:34 -06:00
case uiAttributeStylisticAlternate16 :
2017-02-20 13:59:43 -06:00
boolspec ( spec , " ss16 " , f , data ) ;
2017-02-14 18:00:35 -06:00
return ;
2017-02-24 17:19:34 -06:00
case uiAttributeStylisticAlternate17 :
2017-02-20 13:59:43 -06:00
boolspec ( spec , " ss17 " , f , data ) ;
2017-02-14 18:00:35 -06:00
return ;
2017-02-24 17:19:34 -06:00
case uiAttributeStylisticAlternate18 :
2017-02-20 13:59:43 -06:00
boolspec ( spec , " ss18 " , f , data ) ;
2017-02-14 18:00:35 -06:00
return ;
2017-02-24 17:19:34 -06:00
case uiAttributeStylisticAlternate19 :
2017-02-20 13:59:43 -06:00
boolspec ( spec , " ss19 " , f , data ) ;
2017-02-14 18:00:35 -06:00
return ;
2017-02-24 17:19:34 -06:00
case uiAttributeStylisticAlternate20 :
2017-02-20 13:59:43 -06:00
boolspec ( spec , " ss20 " , f , data ) ;
2017-02-14 18:00:35 -06:00
return ;
case uiAttributeContextualAlternates :
2017-02-20 13:59:43 -06:00
boolspec ( spec , " calt " , f , data ) ;
2017-02-14 18:00:35 -06:00
return ;
case uiAttributeSwashes :
2017-02-20 13:59:43 -06:00
boolspec ( spec , " swsh " , f , data ) ;
2017-02-14 18:00:35 -06:00
return ;
case uiAttributeContextualSwashes :
2017-02-20 13:59:43 -06:00
boolspec ( spec , " cswh " , f , data ) ;
2017-02-14 18:00:35 -06:00
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 ;
}
}
2017-02-14 20:18:56 -06:00
// 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)
2017-02-15 00:34:26 -06:00
// - dnom, numr (fraction parts) — no AAT equivalent...
2017-02-14 21:37:01 -06:00
// - falt, jalt (Arabic support)
2017-02-14 20:18:56 -06:00
// - 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)
2017-02-14 21:37:01 -06:00
//
// 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?
2017-02-14 22:56:20 -06:00
// abvf yes yes
// abvm yes yes
// abvs yes TODO
// akhn yes yes
// blwf yes yes
// blwm yes yes
// blws yes TODO
// cjct yes yes
2017-02-15 00:34:26 -06:00
// curs yes yes
2017-02-14 22:56:20 -06:00
// dist yes yes
2017-02-14 21:37:01 -06:00
// falt TODO TODO
2017-02-14 22:56:20 -06:00
// fin2 yes yes
// fin3 yes yes
// fina yes yes
// half yes yes
// haln yes yes
// init yes yes
// isol yes yes
2017-02-14 21:37:01 -06:00
// jalt TODO TODO
2017-02-14 22:56:20 -06:00
// ljmo yes yes
2017-02-14 21:37:01 -06:00
// locl TODO all horz(!)
2017-02-14 22:56:20 -06:00
// med2 yes yes
// medi yes yes
2017-02-14 21:37:01 -06:00
// mset TODO yes
2017-02-14 22:56:20 -06:00
// nukt yes yes
// pref yes yes
// pres yes yes
// pstf yes yes
// psts yes yes
2017-02-14 21:37:01 -06:00
// rclt TODO all horz(!)
2017-02-14 22:56:20 -06:00
// rkrf yes yes
// rphf yes yes
// tjmo yes yes
// vatu yes yes
// vjmo yes yes