2018-03-04 14:09:27 -06:00
|
|
|
// 11 may 2017
|
|
|
|
#import "uipriv_darwin.h"
|
2018-03-04 14:48:45 -06:00
|
|
|
#import "attrstr.h"
|
2018-03-04 14:09:27 -06:00
|
|
|
|
|
|
|
struct addCTFeatureEntryParams {
|
|
|
|
CFMutableArrayRef array;
|
|
|
|
const void *tagKey;
|
|
|
|
BOOL tagIsNumber;
|
|
|
|
CFNumberType tagType;
|
|
|
|
const void *tagValue;
|
|
|
|
const void *valueKey;
|
|
|
|
CFNumberType valueType;
|
|
|
|
const void *valueValue;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void addCTFeatureEntry(struct addCTFeatureEntryParams *p)
|
|
|
|
{
|
|
|
|
CFDictionaryRef featureDict;
|
|
|
|
CFNumberRef tagNum, valueNum;
|
|
|
|
const void *keys[2], *values[2];
|
|
|
|
|
|
|
|
keys[0] = p->tagKey;
|
|
|
|
tagNum = NULL;
|
|
|
|
values[0] = p->tagValue;
|
|
|
|
if (p->tagIsNumber) {
|
|
|
|
tagNum = CFNumberCreate(NULL, p->tagType, p->tagValue);
|
|
|
|
values[0] = tagNum;
|
|
|
|
}
|
|
|
|
|
|
|
|
keys[1] = p->valueKey;
|
|
|
|
valueNum = CFNumberCreate(NULL, p->valueType, p->valueValue);
|
|
|
|
values[1] = valueNum;
|
|
|
|
|
|
|
|
featureDict = CFDictionaryCreate(NULL,
|
|
|
|
keys, values, 2,
|
|
|
|
// TODO are these correct?
|
|
|
|
&kCFCopyStringDictionaryKeyCallBacks,
|
|
|
|
&kCFTypeDictionaryValueCallBacks);
|
|
|
|
if (featureDict == NULL) {
|
|
|
|
// TODO
|
|
|
|
}
|
|
|
|
CFArrayAppendValue(p->array, featureDict);
|
|
|
|
|
|
|
|
CFRelease(featureDict);
|
|
|
|
CFRelease(valueNum);
|
|
|
|
if (p->tagIsNumber)
|
|
|
|
CFRelease(tagNum);
|
|
|
|
}
|
|
|
|
|
|
|
|
static uiForEach otfArrayForEachAAT(const uiOpenTypeFeatures *otf, char a, char b, char c, char d, uint32_t value, void *data)
|
|
|
|
{
|
|
|
|
__block struct addCTFeatureEntryParams p;
|
|
|
|
|
|
|
|
p.array = (CFMutableArrayRef) data;
|
|
|
|
p.tagIsNumber = YES;
|
2018-03-04 14:53:46 -06:00
|
|
|
uiprivOpenTypeToAAT(a, b, c, d, value, ^(uint16_t type, uint16_t selector) {
|
2018-03-04 14:09:27 -06:00
|
|
|
p.tagKey = kCTFontFeatureTypeIdentifierKey;
|
|
|
|
p.tagType = kCFNumberSInt16Type;
|
|
|
|
p.tagValue = (const SInt16 *) (&type);
|
|
|
|
p.valueKey = kCTFontFeatureSelectorIdentifierKey;
|
|
|
|
p.valueType = kCFNumberSInt16Type;
|
|
|
|
p.valueValue = (const SInt16 *) (&selector);
|
|
|
|
addCTFeatureEntry(&p);
|
|
|
|
});
|
|
|
|
return uiForEachContinue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO find out which fonts differ in AAT small caps and test them with this
|
|
|
|
static uiForEach otfArrayForEachOT(const uiOpenTypeFeatures *otf, char a, char b, char c, char d, uint32_t value, void *data)
|
|
|
|
{
|
|
|
|
struct addCTFeatureEntryParams p;
|
|
|
|
char tagcstr[5];
|
|
|
|
CFStringRef tagstr;
|
|
|
|
|
|
|
|
p.array = (CFMutableArrayRef) data;
|
|
|
|
|
|
|
|
p.tagKey = *FUTURE_kCTFontOpenTypeFeatureTag;
|
|
|
|
p.tagIsNumber = NO;
|
|
|
|
tagcstr[0] = a;
|
|
|
|
tagcstr[1] = b;
|
|
|
|
tagcstr[2] = c;
|
|
|
|
tagcstr[3] = d;
|
|
|
|
tagcstr[4] = '\0';
|
|
|
|
tagstr = CFStringCreateWithCString(NULL, tagcstr, kCFStringEncodingUTF8);
|
|
|
|
if (tagstr == NULL) {
|
|
|
|
// TODO
|
|
|
|
}
|
|
|
|
p.tagValue = tagstr;
|
|
|
|
|
|
|
|
p.valueKey = *FUTURE_kCTFontOpenTypeFeatureValue;
|
|
|
|
p.valueType = kCFNumberSInt32Type;
|
|
|
|
p.valueValue = (const SInt32 *) (&value);
|
|
|
|
addCTFeatureEntry(&p);
|
|
|
|
|
2018-03-09 17:01:23 -06:00
|
|
|
CFRelease(tagstr);
|
2018-03-04 14:09:27 -06:00
|
|
|
return uiForEachContinue;
|
|
|
|
}
|
|
|
|
|
|
|
|
CFArrayRef uiprivOpenTypeFeaturesToCTFeatures(const uiOpenTypeFeatures *otf)
|
|
|
|
{
|
|
|
|
CFMutableArrayRef array;
|
|
|
|
uiOpenTypeFeaturesForEachFunc f;
|
|
|
|
|
|
|
|
array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
|
|
|
|
if (array == NULL) {
|
|
|
|
// TODO
|
|
|
|
}
|
|
|
|
f = otfArrayForEachAAT;
|
|
|
|
if (FUTURE_kCTFontOpenTypeFeatureTag != NULL && FUTURE_kCTFontOpenTypeFeatureValue != NULL)
|
|
|
|
f = otfArrayForEachOT;
|
|
|
|
uiOpenTypeFeaturesForEach(otf, f, array);
|
|
|
|
return array;
|
|
|
|
}
|