And FINALLY cleaned up all the AAT nonsense. Much saner now.
This commit is contained in:
parent
c4dd85bece
commit
91bfceaf71
162
darwin/aat.m
162
darwin/aat.m
|
@ -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);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue