And FINALLY cleaned up all the AAT nonsense. Much saner now.

This commit is contained in:
Pietro Gagliardi 2017-05-30 14:00:58 -04:00
parent c4dd85bece
commit 91bfceaf71
7 changed files with 137 additions and 132 deletions

View File

@ -1,25 +1,18 @@
// 14 february 2017 // 14 february 2017
#import "uipriv_darwin.h" #import "uipriv_darwin.h"
struct openTypeAATParams { static void boolspec(uint32_t value, uint16_t type, uint16_t ifTrue, uint16_t ifFalse, aatBlock f)
void (*doAAT)(uint16_t type, uint16_t selector, void *data);
void *data;
};
#define pcall(p, type, selector) ((*(p->doAAT))(type, selector, p->data))
static void boolspec(uint32_t value, uint16_t type, uint16_t ifTrue, uint16_t ifFalse, struct openTypeAATParams *p)
{ {
// TODO are values other than 1 accepted for true by OpenType itself? (same for the rest of the file) // TODO are values other than 1 accepted for true by OpenType itself? (same for the rest of the file)
if (value != 0) { if (value != 0) {
pcall(p, type, ifTrue); f(type, ifTrue);
return; return;
} }
pcall(p, type, ifFalse); f(type, ifFalse);
} }
// TODO double-check drawtext example to make sure all of these are used properly (I already screwed dlig up by putting clig twice instead) // TODO double-check drawtext example to make sure all of these are used properly (I already screwed dlig up by putting clig twice instead)
static int foreach(char a, char b, char c, char d, uint32_t value, void *data) void openTypeToAAT(char a, char b, char c, char d, uint32_t value, aatBlock f)
{ {
struct openTypeAATParams *p = (struct openTypeAATParams *) data; struct openTypeAATParams *p = (struct openTypeAATParams *) data;
@ -28,25 +21,25 @@ static int foreach(char a, char b, char c, char d, uint32_t value, void *data)
boolspec(value, kLigaturesType, boolspec(value, kLigaturesType,
kCommonLigaturesOnSelector, kCommonLigaturesOnSelector,
kCommonLigaturesOffSelector, kCommonLigaturesOffSelector,
p); f);
break; break;
case mkTag('r', 'l', 'i', 'g'): case mkTag('r', 'l', 'i', 'g'):
boolspec(value, kLigaturesType, boolspec(value, kLigaturesType,
kRequiredLigaturesOnSelector, kRequiredLigaturesOnSelector,
kRequiredLigaturesOffSelector, kRequiredLigaturesOffSelector,
p); f);
break; break;
case mkTag('d', 'l', 'i', 'g'): case mkTag('d', 'l', 'i', 'g'):
boolspec(value, kLigaturesType, boolspec(value, kLigaturesType,
kRareLigaturesOnSelector, kRareLigaturesOnSelector,
kRareLigaturesOffSelector, kRareLigaturesOffSelector,
p); f);
break; break;
case mkTag('c', 'l', 'i', 'g'): case mkTag('c', 'l', 'i', 'g'):
boolspec(value, kLigaturesType, boolspec(value, kLigaturesType,
kContextualLigaturesOnSelector, kContextualLigaturesOnSelector,
kContextualLigaturesOffSelector, kContextualLigaturesOffSelector,
p); f);
break; break;
case mkTag('h', 'l', 'i', 'g'): case mkTag('h', 'l', 'i', 'g'):
// 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 // 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
@ -54,117 +47,117 @@ static int foreach(char a, char b, char c, char d, uint32_t value, void *data)
boolspec(value, kLigaturesType, boolspec(value, kLigaturesType,
kHistoricalLigaturesOnSelector, kHistoricalLigaturesOnSelector,
kHistoricalLigaturesOffSelector, kHistoricalLigaturesOffSelector,
p); f);
break; break;
case mkTag('u', 'n', 'i', 'c'): case mkTag('u', 'n', 'i', 'c'):
// TODO is this correct, or should we provide an else case? // TODO is this correct, or should we provide an else case?
if (value != 0) if (value != 0)
// this is undocumented; it comes from Core Text's internal AAT-to-OpenType conversion table // this is undocumented; it comes from Core Text's internal AAT-to-OpenType conversion table
pcall(p, kLetterCaseType, 14); f(p, kLetterCaseType, 14);
break; break;
// TODO will the following handle all cases properly, or are elses going to be needed? // TODO will the following handle all cases properly, or are elses going to be needed?
case mkTag('p', 'n', 'u', 'm'): case mkTag('p', 'n', 'u', 'm'):
if (value != 0) if (value != 0)
pcall(p, kNumberSpacingType, kProportionalNumbersSelector); f(p, kNumberSpacingType, kProportionalNumbersSelector);
break; break;
case mkTag('t', 'n', 'u', 'm'): case mkTag('t', 'n', 'u', 'm'):
if (value != 0) if (value != 0)
pcall(p, kNumberSpacingType, kMonospacedNumbersSelector); f(p, kNumberSpacingType, kMonospacedNumbersSelector);
break; break;
// TODO will the following handle all cases properly, or are elses going to be needed? // TODO will the following handle all cases properly, or are elses going to be needed?
case mkTag('s', 'u', 'p', 's'): case mkTag('s', 'u', 'p', 's'):
if (value != 0) if (value != 0)
pcall(p, kVerticalPositionType, kSuperiorsSelector); f(p, kVerticalPositionType, kSuperiorsSelector);
break; break;
case mkTag('s', 'u', 'b', 's'): case mkTag('s', 'u', 'b', 's'):
if (value != 0) if (value != 0)
pcall(p, kVerticalPositionType, kInferiorsSelector); f(p, kVerticalPositionType, kInferiorsSelector);
break; break;
case mkTag('o', 'r', 'd', 'n'): case mkTag('o', 'r', 'd', 'n'):
if (value != 0) if (value != 0)
pcall(p, kVerticalPositionType, kOrdinalsSelector); f(p, kVerticalPositionType, kOrdinalsSelector);
break; break;
case mkTag('s', 'i', 'n', 'f'): case mkTag('s', 'i', 'n', 'f'):
if (value != 0) if (value != 0)
pcall(p, kVerticalPositionType, kScientificInferiorsSelector); f(p, kVerticalPositionType, kScientificInferiorsSelector);
break; break;
// TODO will the following handle all cases properly, or are elses going to be needed? // TODO will the following handle all cases properly, or are elses going to be needed?
case mkTag('a', 'f', 'r', 'c'): case mkTag('a', 'f', 'r', 'c'):
if (value != 0) if (value != 0)
pcall(p, kFractionsType, kVerticalFractionsSelector); f(p, kFractionsType, kVerticalFractionsSelector);
break; break;
case mkTag('f', 'r', 'a', 'c'): case mkTag('f', 'r', 'a', 'c'):
if (value != 0) if (value != 0)
pcall(p, kFractionsType, kDiagonalFractionsSelector); f(p, kFractionsType, kDiagonalFractionsSelector);
break; break;
case mkTag('z', 'e', 'r', 'o'): case mkTag('z', 'e', 'r', 'o'):
boolspec(value, kTypographicExtrasType, boolspec(value, kTypographicExtrasType,
kSlashedZeroOnSelector, kSlashedZeroOnSelector,
kSlashedZeroOffSelector, kSlashedZeroOffSelector,
p); f);
break; break;
case mkTag('m', 'g', 'r', 'k'): case mkTag('m', 'g', 'r', 'k'):
boolspec(value, kMathematicalExtrasType, boolspec(value, kMathematicalExtrasType,
kMathematicalGreekOnSelector, kMathematicalGreekOnSelector,
kMathematicalGreekOffSelector, kMathematicalGreekOffSelector,
p); f);
break; break;
case mkTag('o', 'r', 'n', 'm'): case mkTag('o', 'r', 'n', 'm'):
pcall(p, kOrnamentSetsType, (uint16_t) value); f(p, kOrnamentSetsType, (uint16_t) value);
break; break;
case mkTag('a', 'a', 'l', 't'): case mkTag('a', 'a', 'l', 't'):
pcall(p, kCharacterAlternativesType, (uint16_t) value); f(p, kCharacterAlternativesType, (uint16_t) value);
break; break;
case mkTag('t', 'i', 't', 'l'): case mkTag('t', 'i', 't', 'l'):
// TODO is this correct, or should we provide an else case? // TODO is this correct, or should we provide an else case?
if (value != 0) if (value != 0)
pcall(p, kStyleOptionsType, kTitlingCapsSelector); f(p, kStyleOptionsType, kTitlingCapsSelector);
break; break;
// TODO will the following handle all cases properly, or are elses going to be needed? // TODO will the following handle all cases properly, or are elses going to be needed?
case mkTag('t', 'r', 'a', 'd'): case mkTag('t', 'r', 'a', 'd'):
if (value != 0) if (value != 0)
pcall(p, kCharacterShapeType, kTraditionalCharactersSelector); f(p, kCharacterShapeType, kTraditionalCharactersSelector);
break; break;
case mkTag('s', 'm', 'p', 'l'): case mkTag('s', 'm', 'p', 'l'):
if (value != 0) if (value != 0)
pcall(p, kCharacterShapeType, kSimplifiedCharactersSelector); f(p, kCharacterShapeType, kSimplifiedCharactersSelector);
break; break;
case mkTag('j', 'p', '7', '8'): case mkTag('j', 'p', '7', '8'):
if (value != 0) if (value != 0)
pcall(p, kCharacterShapeType, kJIS1978CharactersSelector); f(p, kCharacterShapeType, kJIS1978CharactersSelector);
break; break;
case mkTag('j', 'p', '8', '3'): case mkTag('j', 'p', '8', '3'):
if (value != 0) if (value != 0)
pcall(p, kCharacterShapeType, kJIS1983CharactersSelector); f(p, kCharacterShapeType, kJIS1983CharactersSelector);
break; break;
case mkTag('j', 'p', '9', '0'): case mkTag('j', 'p', '9', '0'):
if (value != 0) if (value != 0)
pcall(p, kCharacterShapeType, kJIS1990CharactersSelector); f(p, kCharacterShapeType, kJIS1990CharactersSelector);
break; break;
case mkTag('e', 'x', 'p', 't'): case mkTag('e', 'x', 'p', 't'):
if (value != 0) if (value != 0)
pcall(p, kCharacterShapeType, kExpertCharactersSelector); f(p, kCharacterShapeType, kExpertCharactersSelector);
break; break;
case mkTag('j', 'p', '0', '4'): case mkTag('j', 'p', '0', '4'):
if (value != 0) if (value != 0)
pcall(p, kCharacterShapeType, kJIS2004CharactersSelector); f(p, kCharacterShapeType, kJIS2004CharactersSelector);
break; break;
case mkTag('h', 'o', 'j', 'o'): case mkTag('h', 'o', 'j', 'o'):
if (value != 0) if (value != 0)
pcall(p, kCharacterShapeType, kHojoCharactersSelector); f(p, kCharacterShapeType, kHojoCharactersSelector);
break; break;
case mkTag('n', 'l', 'c', 'k'): case mkTag('n', 'l', 'c', 'k'):
if (value != 0) if (value != 0)
pcall(p, kCharacterShapeType, kNLCCharactersSelector); f(p, kCharacterShapeType, kNLCCharactersSelector);
break; break;
case mkTag('t', 'n', 'a', 'm'): case mkTag('t', 'n', 'a', 'm'):
if (value != 0) if (value != 0)
pcall(p, kCharacterShapeType, kTraditionalNamesCharactersSelector); f(p, kCharacterShapeType, kTraditionalNamesCharactersSelector);
break; break;
case mkTag('o', 'n', 'u', 'm'): case mkTag('o', 'n', 'u', 'm'):
@ -173,201 +166,201 @@ static int foreach(char a, char b, char c, char d, uint32_t value, void *data)
case mkTag('l', 'n', 'u', 'm'): case mkTag('l', 'n', 'u', 'm'):
// TODO is this correct, or should we provide an else case? // TODO is this correct, or should we provide an else case?
if (value != 0) if (value != 0)
pcall(p, kNumberCaseType, kLowerCaseNumbersSelector); f(p, kNumberCaseType, kLowerCaseNumbersSelector);
break; break;
case mkTag('h', 'n', 'g', 'l'): case mkTag('h', 'n', 'g', 'l'):
// TODO is this correct, or should we provide an else case? // TODO is this correct, or should we provide an else case?
if (value != 0) if (value != 0)
pcall(p, kTransliterationType, kHanjaToHangulSelector); f(p, kTransliterationType, kHanjaToHangulSelector);
break; break;
case mkTag('n', 'a', 'l', 't'): case mkTag('n', 'a', 'l', 't'):
pcall(p, kAnnotationType, (uint16_t) value); f(p, kAnnotationType, (uint16_t) value);
break; break;
case mkTag('r', 'u', 'b', 'y'): case mkTag('r', 'u', 'b', 'y'):
// include this for completeness // include this for completeness
boolspec(value, kRubyKanaType, boolspec(value, kRubyKanaType,
kRubyKanaSelector, kRubyKanaSelector,
kNoRubyKanaSelector, kNoRubyKanaSelector,
p); f);
// this is the current one // this is the current one
boolspec(value, kRubyKanaType, boolspec(value, kRubyKanaType,
kRubyKanaOnSelector, kRubyKanaOnSelector,
kRubyKanaOffSelector, kRubyKanaOffSelector,
p); f);
break; break;
case mkTag('i', 't', 'a', 'l'): case mkTag('i', 't', 'a', 'l'):
// include this for completeness // include this for completeness
boolspec(value, kItalicCJKRomanType, boolspec(value, kItalicCJKRomanType,
kCJKItalicRomanSelector, kCJKItalicRomanSelector,
kNoCJKItalicRomanSelector, kNoCJKItalicRomanSelector,
p); f);
// this is the current one // this is the current one
boolspec(value, kItalicCJKRomanType, boolspec(value, kItalicCJKRomanType,
kCJKItalicRomanOnSelector, kCJKItalicRomanOnSelector,
kCJKItalicRomanOffSelector, kCJKItalicRomanOffSelector,
p); f);
break; break;
case mkTag('c', 'a', 's', 'e'): case mkTag('c', 'a', 's', 'e'):
boolspec(value, kCaseSensitiveLayoutType, boolspec(value, kCaseSensitiveLayoutType,
kCaseSensitiveLayoutOnSelector, kCaseSensitiveLayoutOnSelector,
kCaseSensitiveLayoutOffSelector, kCaseSensitiveLayoutOffSelector,
p); f);
break; break;
case mkTag('c', 'p', 's', 'p'): case mkTag('c', 'p', 's', 'p'):
boolspec(value, kCaseSensitiveLayoutType, boolspec(value, kCaseSensitiveLayoutType,
kCaseSensitiveSpacingOnSelector, kCaseSensitiveSpacingOnSelector,
kCaseSensitiveSpacingOffSelector, kCaseSensitiveSpacingOffSelector,
p); f);
break; break;
case mkTag('h', 'k', 'n', 'a'): case mkTag('h', 'k', 'n', 'a'):
boolspec(value, kAlternateKanaType, boolspec(value, kAlternateKanaType,
kAlternateHorizKanaOnSelector, kAlternateHorizKanaOnSelector,
kAlternateHorizKanaOffSelector, kAlternateHorizKanaOffSelector,
p); f);
break; break;
case mkTag('v', 'k', 'n', 'a'): case mkTag('v', 'k', 'n', 'a'):
boolspec(value, kAlternateKanaType, boolspec(value, kAlternateKanaType,
kAlternateVertKanaOnSelector, kAlternateVertKanaOnSelector,
kAlternateVertKanaOffSelector, kAlternateVertKanaOffSelector,
p); f);
break; break;
case mkTag('s', 's', '0', '1'): case mkTag('s', 's', '0', '1'):
boolspec(value, kStylisticAlternativesType, boolspec(value, kStylisticAlternativesType,
kStylisticAltOneOnSelector, kStylisticAltOneOnSelector,
kStylisticAltOneOffSelector, kStylisticAltOneOffSelector,
p); f);
break; break;
case mkTag('s', 's', '0', '2'): case mkTag('s', 's', '0', '2'):
boolspec(value, kStylisticAlternativesType, boolspec(value, kStylisticAlternativesType,
kStylisticAltTwoOnSelector, kStylisticAltTwoOnSelector,
kStylisticAltTwoOffSelector, kStylisticAltTwoOffSelector,
p); f);
break; break;
case mkTag('s', 's', '0', '3'): case mkTag('s', 's', '0', '3'):
boolspec(value, kStylisticAlternativesType, boolspec(value, kStylisticAlternativesType,
kStylisticAltThreeOnSelector, kStylisticAltThreeOnSelector,
kStylisticAltThreeOffSelector, kStylisticAltThreeOffSelector,
p); f);
break; break;
case mkTag('s', 's', '0', '4'): case mkTag('s', 's', '0', '4'):
boolspec(value, kStylisticAlternativesType, boolspec(value, kStylisticAlternativesType,
kStylisticAltFourOnSelector, kStylisticAltFourOnSelector,
kStylisticAltFourOffSelector, kStylisticAltFourOffSelector,
p); f);
break; break;
case mkTag('s', 's', '0', '5'): case mkTag('s', 's', '0', '5'):
boolspec(value, kStylisticAlternativesType, boolspec(value, kStylisticAlternativesType,
kStylisticAltFiveOnSelector, kStylisticAltFiveOnSelector,
kStylisticAltFiveOffSelector, kStylisticAltFiveOffSelector,
p); f);
break; break;
case mkTag('s', 's', '0', '6'): case mkTag('s', 's', '0', '6'):
boolspec(value, kStylisticAlternativesType, boolspec(value, kStylisticAlternativesType,
kStylisticAltSixOnSelector, kStylisticAltSixOnSelector,
kStylisticAltSixOffSelector, kStylisticAltSixOffSelector,
p); f);
break; break;
case mkTag('s', 's', '0', '7'): case mkTag('s', 's', '0', '7'):
boolspec(value, kStylisticAlternativesType, boolspec(value, kStylisticAlternativesType,
kStylisticAltSevenOnSelector, kStylisticAltSevenOnSelector,
kStylisticAltSevenOffSelector, kStylisticAltSevenOffSelector,
p); f);
break; break;
case mkTag('s', 's', '0', '8'): case mkTag('s', 's', '0', '8'):
boolspec(value, kStylisticAlternativesType, boolspec(value, kStylisticAlternativesType,
kStylisticAltEightOnSelector, kStylisticAltEightOnSelector,
kStylisticAltEightOffSelector, kStylisticAltEightOffSelector,
p); f);
break; break;
case mkTag('s', 's', '0', '9'): case mkTag('s', 's', '0', '9'):
boolspec(value, kStylisticAlternativesType, boolspec(value, kStylisticAlternativesType,
kStylisticAltNineOnSelector, kStylisticAltNineOnSelector,
kStylisticAltNineOffSelector, kStylisticAltNineOffSelector,
p); f);
break; break;
case mkTag('s', 's', '1', '0'): case mkTag('s', 's', '1', '0'):
boolspec(value, kStylisticAlternativesType, boolspec(value, kStylisticAlternativesType,
kStylisticAltTenOnSelector, kStylisticAltTenOnSelector,
kStylisticAltTenOffSelector, kStylisticAltTenOffSelector,
p); f);
break; break;
case mkTag('s', 's', '1', '1'): case mkTag('s', 's', '1', '1'):
boolspec(value, kStylisticAlternativesType, boolspec(value, kStylisticAlternativesType,
kStylisticAltElevenOnSelector, kStylisticAltElevenOnSelector,
kStylisticAltElevenOffSelector, kStylisticAltElevenOffSelector,
p); f);
break; break;
case mkTag('s', 's', '1', '2'): case mkTag('s', 's', '1', '2'):
boolspec(value, kStylisticAlternativesType, boolspec(value, kStylisticAlternativesType,
kStylisticAltTwelveOnSelector, kStylisticAltTwelveOnSelector,
kStylisticAltTwelveOffSelector, kStylisticAltTwelveOffSelector,
p); f);
break; break;
case mkTag('s', 's', '1', '3'): case mkTag('s', 's', '1', '3'):
boolspec(value, kStylisticAlternativesType, boolspec(value, kStylisticAlternativesType,
kStylisticAltThirteenOnSelector, kStylisticAltThirteenOnSelector,
kStylisticAltThirteenOffSelector, kStylisticAltThirteenOffSelector,
p); f);
break; break;
case mkTag('s', 's', '1', '4'): case mkTag('s', 's', '1', '4'):
boolspec(value, kStylisticAlternativesType, boolspec(value, kStylisticAlternativesType,
kStylisticAltFourteenOnSelector, kStylisticAltFourteenOnSelector,
kStylisticAltFourteenOffSelector, kStylisticAltFourteenOffSelector,
p); f);
break; break;
case mkTag('s', 's', '1', '5'): case mkTag('s', 's', '1', '5'):
boolspec(value, kStylisticAlternativesType, boolspec(value, kStylisticAlternativesType,
kStylisticAltFifteenOnSelector, kStylisticAltFifteenOnSelector,
kStylisticAltFifteenOffSelector, kStylisticAltFifteenOffSelector,
p); f);
break; break;
case mkTag('s', 's', '1', '6'): case mkTag('s', 's', '1', '6'):
boolspec(value, kStylisticAlternativesType, boolspec(value, kStylisticAlternativesType,
kStylisticAltSixteenOnSelector, kStylisticAltSixteenOnSelector,
kStylisticAltSixteenOffSelector, kStylisticAltSixteenOffSelector,
p); f);
break; break;
case mkTag('s', 's', '1', '7'): case mkTag('s', 's', '1', '7'):
boolspec(value, kStylisticAlternativesType, boolspec(value, kStylisticAlternativesType,
kStylisticAltSeventeenOnSelector, kStylisticAltSeventeenOnSelector,
kStylisticAltSeventeenOffSelector, kStylisticAltSeventeenOffSelector,
p); f);
break; break;
case mkTag('s', 's', '1', '8'): case mkTag('s', 's', '1', '8'):
boolspec(value, kStylisticAlternativesType, boolspec(value, kStylisticAlternativesType,
kStylisticAltEighteenOnSelector, kStylisticAltEighteenOnSelector,
kStylisticAltEighteenOffSelector, kStylisticAltEighteenOffSelector,
p); f);
break; break;
case mkTag('s', 's', '1', '9'): case mkTag('s', 's', '1', '9'):
boolspec(value, kStylisticAlternativesType, boolspec(value, kStylisticAlternativesType,
kStylisticAltNineteenOnSelector, kStylisticAltNineteenOnSelector,
kStylisticAltNineteenOffSelector, kStylisticAltNineteenOffSelector,
p); f);
break; break;
case mkTag('s', 's', '2', '0'): case mkTag('s', 's', '2', '0'):
boolspec(value, kStylisticAlternativesType, boolspec(value, kStylisticAlternativesType,
kStylisticAltTwentyOnSelector, kStylisticAltTwentyOnSelector,
kStylisticAltTwentyOffSelector, kStylisticAltTwentyOffSelector,
p); f);
break; break;
case mkTag('c', 'a', 'l', 't'): case mkTag('c', 'a', 'l', 't'):
boolspec(value, kContextualAlternatesType, boolspec(value, kContextualAlternatesType,
kContextualAlternatesOnSelector, kContextualAlternatesOnSelector,
kContextualAlternatesOffSelector, kContextualAlternatesOffSelector,
p); f);
break; break;
case mkTag('s', 'w', 's', 'h'): case mkTag('s', 'w', 's', 'h'):
boolspec(value, kContextualAlternatesType, boolspec(value, kContextualAlternatesType,
kSwashAlternatesOnSelector, kSwashAlternatesOnSelector,
kSwashAlternatesOffSelector, kSwashAlternatesOffSelector,
p); f);
break; break;
case mkTag('c', 's', 'w', 'h'): case mkTag('c', 's', 'w', 'h'):
boolspec(value, kContextualAlternatesType, boolspec(value, kContextualAlternatesType,
kContextualSwashAlternatesOnSelector, kContextualSwashAlternatesOnSelector,
kContextualSwashAlternatesOffSelector, kContextualSwashAlternatesOffSelector,
p); f);
break; break;
// TODO will the following handle all cases properly, or are elses going to be needed? // TODO will the following handle all cases properly, or are elses going to be needed?
@ -375,35 +368,26 @@ static int foreach(char a, char b, char c, char d, uint32_t value, void *data)
if (value != 0) { if (value != 0) {
// include this for compatibility (some fonts that come with OS X still use this!) // include this for compatibility (some fonts that come with OS X still use this!)
// TODO make it boolean? // TODO make it boolean?
pcall(p, kLetterCaseType, kSmallCapsSelector); f(p, kLetterCaseType, kSmallCapsSelector);
// this is the current one // this is the current one
pcall(p, kLowerCaseType, kLowerCaseSmallCapsSelector); f(p, kLowerCaseType, kLowerCaseSmallCapsSelector);
} }
break; break;
case mkTag('p', 'c', 'a', 'p'): case mkTag('p', 'c', 'a', 'p'):
if (value != 0) if (value != 0)
pcall(p, kLowerCaseType, kLowerCasePetiteCapsSelector); f(p, kLowerCaseType, kLowerCasePetiteCapsSelector);
break; break;
// TODO will the following handle all cases properly, or are elses going to be needed? // TODO will the following handle all cases properly, or are elses going to be needed?
case mkTag('c', '2', 's', 'c'): case mkTag('c', '2', 's', 'c'):
if (value != 0) if (value != 0)
pcall(p, kUpperCaseType, kUpperCaseSmallCapsSelector); f(p, kUpperCaseType, kUpperCaseSmallCapsSelector);
break; break;
case mkTag('c', '2', 'p', 'c'): case mkTag('c', '2', 'p', 'c'):
if (value != 0) if (value != 0)
pcall(p, kUpperCaseType, kUpperCasePetiteCapsSelector); f(p, kUpperCaseType, kUpperCasePetiteCapsSelector);
break; break;
} }
// TODO handle this properly // TODO handle this properly
return 0; // (it used to return 0 when this still returned the number of selectors produced but IDK what properly is anymore)
}
void openTypeToAAT(uiOpenTypeFeatures *otf, void (*doAAT)(uint16_t type, uint16_t selector, void *data), void *data)
{
struct openTypeAATParams p;
p.doAAT = doAAT;
p.data = data;
uiOpenTypeFeaturesForEach(otf, foreach, &p);
} }

View File

@ -258,50 +258,21 @@ CTFontDescriptorRef fontdescToCTFontDescriptor(uiDrawFontDescriptor *fd)
CTFontDescriptorRef fontdescAppendFeatures(CTFontDescriptorRef desc, const uiOpenTypeFeatures *otf) CTFontDescriptorRef fontdescAppendFeatures(CTFontDescriptorRef desc, const uiOpenTypeFeatures *otf)
{ {
CTFontDescriptorRef new; CTFontDescriptorRef new;
CFMutableArrayRef outerArray; CFMutableArrayRef featuresArray;
CFDictionaryRef innerDict; CFDictionaryRef attrs;
CFNumberRef numType, numSelector;
const void *keys[2], *values[2];
size_t i;
outerArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
if (outerArray == NULL) {
// TODO
}
keys[0] = kCTFontFeatureTypeIdentifierKey;
keys[1] = kCTFontFeatureSelectorIdentifierKey;
for (i = 0; i < n; i++) {
numType = CFNumberCreate(NULL, kCFNumberSInt16Type,
(const SInt16 *) (types + i));
numSelector = CFNumberCreate(NULL, kCFNumberSInt16Type,
(const SInt16 *) (selectors + i));
values[0] = numType;
values[1] = numSelector;
innerDict = CFDictionaryCreate(NULL,
keys, values, 2,
// TODO are these correct?
&kCFCopyStringDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
if (innerDict == NULL) {
// TODO
}
CFArrayAppendValue(outerArray, innerDict);
CFRelease(innerDict);
CFRelease(numSelector);
CFRelease(numType);
}
featuresArray = otfToFeaturesArray(otf);
keys[0] = kCTFontFeatureSettingsAttribute; keys[0] = kCTFontFeatureSettingsAttribute;
values[0] = outerArray; values[0] = featuresArray;
innerDict = CFDictionaryCreate(NULL, attrs = CFDictionaryCreate(NULL,
keys, values, 1, keys, values, 1,
// TODO are these correct? // TODO are these correct?
&kCFCopyStringDictionaryKeyCallBacks, &kCFCopyStringDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks); &kCFTypeDictionaryValueCallBacks);
CFRelease(outerArray); CFRelease(featuresArray);
new = CTFontDescriptorCreateCopyWithAttributes(desc, innerDict); new = CTFontDescriptorCreateCopyWithAttributes(desc, attrs);
CFRelease(attrs);
CFRelease(desc); CFRelease(desc);
CFRelease(innerDict);
return new; return new;
} }

View File

@ -63,7 +63,7 @@ int uiOpenTypeFeaturesGet(uiOpenTypeFeatures *otf, char a, char b, char c, char
return 1; return 1;
} }
void uiOpenTypeFeaturesForEach(uiOpenTypeFeatures *otf, uiOpenTypeFeaturesForEachFunc f, void *data) void uiOpenTypeFeaturesForEach(const uiOpenTypeFeatures *otf, uiOpenTypeFeaturesForEachFunc f, void *data)
{ {
[otf->tags enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *stop) { [otf->tags enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *stop) {
NSNumber *tn = (NSNumber *) key; NSNumber *tn = (NSNumber *) key;
@ -87,4 +87,51 @@ int uiOpenTypeFeaturesEqual(const uiOpenTypeFeatures *a, const uiOpenTypeFeature
return [a->tags isEqualToDictionary:b->tags]; return [a->tags isEqualToDictionary:b->tags];
} }
// actual conversion to a feature dictionary is handled in aat.m; see there for details // TODO explain all this
// TODO rename outerArray and innerDict (the names made sense when this was part of fontdescAppendFeatures(), but not here)
// TODO make all this use enumerateKeysAndObjects (which requires duplicating code)?
static int otfArrayForEach(char a, char b, char c, char d, uint32_t value, void *data)
{
CFMutableArrayRef outerArray = (CFMutableArrayRef) data;
const void *keys[2], *values[2];
keys[0] = kCTFontFeatureTypeIdentifierKey;
keys[1] = kCTFontFeatureSelectorIdentifierKey;
openTypeToAAT(a, b, c, d, value, ^(uint16_t type, uint16_t selector) {
CFDictionaryRef innerDict;
CFNumberRef numType, numSelector;
numType = CFNumberCreate(NULL, kCFNumberSInt16Type,
(const SInt16 *) (&type));
numSelector = CFNumberCreate(NULL, kCFNumberSInt16Type,
(const SInt16 *) (&selector));
values[0] = numType;
values[1] = numSelector;
innerDict = CFDictionaryCreate(NULL,
keys, values, 2,
// TODO are these correct?
&kCFCopyStringDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
if (innerDict == NULL) {
// TODO
}
CFArrayAppendValue(p->outerArray, innerDict);
CFRelease(innerDict);
CFRelease(numSelector);
CFRelease(numType);
});
// TODO
return 0;
}
CFArrayRef otfToFeaturesArray(const uiOpenTypeFeatures *otf)
{
CFMutableArrayRef outerArray;
outerArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
if (outerArray == NULL) {
// TODO
}
uiOpenTypeFeaturesForEach(otf, otfArrayForEach, outerArray);
return outerArray;
}

View File

@ -153,7 +153,8 @@ typedef void (^backgroundBlock)(uiDrawContext *c, uiDrawTextLayout *layout, doub
extern CFAttributedStringRef attrstrToCoreFoundation(uiDrawTextLayoutParams *p, NSArray **backgroundBlocks); extern CFAttributedStringRef attrstrToCoreFoundation(uiDrawTextLayoutParams *p, NSArray **backgroundBlocks);
// aat.m // aat.m
extern void openTypeToAAT(uiOpenTypeFeatures *otf, void (*doAAT)(uint16_t type, uint16_t selector, void *data), void *data); typedef void (^aatBlock)(uint16_t type, uint16_t selector);
extern void openTypeToAAT(char a, char b, char c, char d, uint32_t value, aatBlock f);
// opentype.m // opentype.m
// TODO this is only used by opentype.m and aat.m; figure out some better way to handle this // TODO this is only used by opentype.m and aat.m; figure out some better way to handle this
@ -164,6 +165,7 @@ extern void openTypeToAAT(uiOpenTypeFeatures *otf, void (*doAAT)(uint16_t type,
(x8tox32(b) << 16) | \ (x8tox32(b) << 16) | \
(x8tox32(c) << 8) | \ (x8tox32(c) << 8) | \
x8tox32(d)) x8tox32(d))
extern CFArrayRef otfToFeaturesArray(const uiOpenTypeFeatures *otf);
// future.m // future.m
extern CFStringRef *FUTURE_kCTFontOpenTypeFeatureTag; extern CFStringRef *FUTURE_kCTFontOpenTypeFeatureTag;

View File

@ -64,7 +64,8 @@ _UI_EXTERN uiOpenTypeFeatures *uiOpenTypeFeaturesClone(const uiOpenTypeFeatures
_UI_EXTERN void uiOpenTypeFeaturesAdd(uiOpenTypeFeatures *otf, char a, char b, char c, char d, uint32_t value); _UI_EXTERN void uiOpenTypeFeaturesAdd(uiOpenTypeFeatures *otf, char a, char b, char c, char d, uint32_t value);
_UI_EXTERN void uiOpenTypeFeaturesRemove(uiOpenTypeFeatures *otf, char a, char b, char c, char d); _UI_EXTERN void uiOpenTypeFeaturesRemove(uiOpenTypeFeatures *otf, char a, char b, char c, char d);
_UI_EXTERN int uiOpenTypeFeaturesGet(uiOpenTypeFeatures *otf, char a, char b, char c, char d, uint32_t *value); _UI_EXTERN int uiOpenTypeFeaturesGet(uiOpenTypeFeatures *otf, char a, char b, char c, char d, uint32_t *value);
_UI_EXTERN void uiOpenTypeFeaturesForEach(uiOpenTypeFeatures *otf, uiOpenTypeFeaturesForEachFunc f, void *data); // TODO make other enumerators const (and in general const-correct everything)
_UI_EXTERN void uiOpenTypeFeaturesForEach(const uiOpenTypeFeatures *otf, uiOpenTypeFeaturesForEachFunc f, void *data);
_UI_EXTERN int uiOpenTypeFeaturesEqual(const uiOpenTypeFeatures *a, const uiOpenTypeFeatures *b); _UI_EXTERN int uiOpenTypeFeaturesEqual(const uiOpenTypeFeatures *a, const uiOpenTypeFeatures *b);
typedef struct uiAttributeSpec uiAttributeSpec; typedef struct uiAttributeSpec uiAttributeSpec;

View File

@ -96,7 +96,7 @@ static void foreach(gpointer key, gpointer value, gpointer data)
(*(ofe->f))((char) a, (char) b, (char) c, (char) d, GPOINTER_TO_INT(value), ofe->data); (*(ofe->f))((char) a, (char) b, (char) c, (char) d, GPOINTER_TO_INT(value), ofe->data);
} }
void uiOpenTypeFeaturesForEach(uiOpenTypeFeatures *otf, uiOpenTypeFeaturesForEachFunc f, void *data) void uiOpenTypeFeaturesForEach(const uiOpenTypeFeatures *otf, uiOpenTypeFeaturesForEachFunc f, void *data)
{ {
struct otfForEach ofe; struct otfForEach ofe;

View File

@ -57,7 +57,7 @@ int uiOpenTypeFeaturesGet(uiOpenTypeFeatures *otf, char a, char b, char c, char
return 1; return 1;
} }
void uiOpenTypeFeaturesForEach(uiOpenTypeFeatures *otf, uiOpenTypeFeaturesForEachFunc f, void *data) void uiOpenTypeFeaturesForEach(const uiOpenTypeFeatures *otf, uiOpenTypeFeaturesForEachFunc f, void *data)
{ {
tagmap::const_iterator iter, end; tagmap::const_iterator iter, end;