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

View File

@ -258,50 +258,21 @@ CTFontDescriptorRef fontdescToCTFontDescriptor(uiDrawFontDescriptor *fd)
CTFontDescriptorRef fontdescAppendFeatures(CTFontDescriptorRef desc, const uiOpenTypeFeatures *otf)
{
CTFontDescriptorRef new;
CFMutableArrayRef outerArray;
CFDictionaryRef innerDict;
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);
}
CFMutableArrayRef featuresArray;
CFDictionaryRef attrs;
featuresArray = otfToFeaturesArray(otf);
keys[0] = kCTFontFeatureSettingsAttribute;
values[0] = outerArray;
innerDict = CFDictionaryCreate(NULL,
values[0] = featuresArray;
attrs = CFDictionaryCreate(NULL,
keys, values, 1,
// TODO are these correct?
&kCFCopyStringDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
CFRelease(outerArray);
new = CTFontDescriptorCreateCopyWithAttributes(desc, innerDict);
CFRelease(featuresArray);
new = CTFontDescriptorCreateCopyWithAttributes(desc, attrs);
CFRelease(attrs);
CFRelease(desc);
CFRelease(innerDict);
return new;
}

View File

@ -63,7 +63,7 @@ int uiOpenTypeFeaturesGet(uiOpenTypeFeatures *otf, char a, char b, char c, char
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) {
NSNumber *tn = (NSNumber *) key;
@ -87,4 +87,51 @@ int uiOpenTypeFeaturesEqual(const uiOpenTypeFeatures *a, const uiOpenTypeFeature
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);
// 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
// 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(c) << 8) | \
x8tox32(d))
extern CFArrayRef otfToFeaturesArray(const uiOpenTypeFeatures *otf);
// future.m
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 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 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);
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);
}
void uiOpenTypeFeaturesForEach(uiOpenTypeFeatures *otf, uiOpenTypeFeaturesForEachFunc f, void *data)
void uiOpenTypeFeaturesForEach(const uiOpenTypeFeatures *otf, uiOpenTypeFeaturesForEachFunc f, void *data)
{
struct otfForEach ofe;

View File

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