libui/darwin/opentype.m

192 lines
5.5 KiB
Objective-C

// 11 may 2017
#import "uipriv_darwin.h"
struct uiOpenTypeFeatures {
NSMutableDictionary *tags;
};
uiOpenTypeFeatures *uiNewOpenTypeFeatures(void)
{
uiOpenTypeFeatures *otf;
otf = uiNew(uiOpenTypeFeatures);
otf->tags = [NSMutableDictionary new];
return otf;
}
void uiFreeOpenTypeFeatures(uiOpenTypeFeatures *otf)
{
[otf->tags release];
uiFree(otf);
}
uiOpenTypeFeatures *uiOpenTypeFeaturesClone(const uiOpenTypeFeatures *otf)
{
uiOpenTypeFeatures *out;
out = uiNew(uiOpenTypeFeatures);
out->tags = [otf->tags mutableCopy];
return out;
}
// why are there no NSNumber methods for stdint.h or the equivalent core foundation types?...
#define mkMapObject(tag) [NSNumber numberWithUnsignedLongLong:((unsigned long long) tag)]
#define mapObjectValue(num) ((uint32_t) [num unsignedLongLongValue])
void uiOpenTypeFeaturesAdd(uiOpenTypeFeatures *otf, char a, char b, char c, char d, uint32_t value)
{
NSNumber *tn, *vn;
tn = mkMapObject(mkTag(a, b, c, d));
vn = mkMapObject(value);
[otf->tags setObject:vn forKey:tn];
}
void uiOpenTypeFeaturesRemove(uiOpenTypeFeatures *otf, char a, char b, char c, char d)
{
NSNumber *tn;
tn = mkMapObject(mkTag(a, b, c, d));
// documented as doing nothing if tn is not in otf->tags
[otf->tags removeObjectForKey:tn];
}
// TODO will the const wreck stuff up?
int uiOpenTypeFeaturesGet(const uiOpenTypeFeatures *otf, char a, char b, char c, char d, uint32_t *value)
{
NSNumber *tn, *vn;
tn = mkMapObject(mkTag(a, b, c, d));
vn = (NSNumber *) [otf->tags objectForKey:tn];
if (vn == nil)
return 0;
*value = mapObjectValue(vn);
// TODO release vn?
return 1;
}
void uiOpenTypeFeaturesForEach(const uiOpenTypeFeatures *otf, uiOpenTypeFeaturesForEachFunc f, void *data)
{
[otf->tags enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *stop) {
NSNumber *tn = (NSNumber *) key;
NSNumber *vn = (NSNumber *) value;
uint32_t tag;
uint8_t a, b, c, d;
uiForEach ret;
tag = mapObjectValue(tn);
a = (uint8_t) ((tag >> 24) & 0xFF);
b = (uint8_t) ((tag >> 16) & 0xFF);
c = (uint8_t) ((tag >> 8) & 0xFF);
d = (uint8_t) (tag & 0xFF);
ret = (*f)(otf, (char) a, (char) b, (char) c, (char) d,
mapObjectValue(vn), data);
// TODO for all: require exact match?
if (ret == uiForEachStop)
*stop = YES;
}];
}
int uiOpenTypeFeaturesEqual(const uiOpenTypeFeatures *a, const uiOpenTypeFeatures *b)
{
if (a == NULL && b == NULL)
return 1;
if (a == NULL || b == NULL)
return 0;
return [a->tags isEqualToDictionary:b->tags];
}
// 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 uiForEach otfArrayForEachAAT(const uiOpenTypeFeatures *otf, char a, char b, char c, char d, uint32_t value, void *data)
{
CFMutableArrayRef outerArray = (CFMutableArrayRef) data;
openTypeToAAT(a, b, c, d, value, ^(uint16_t type, uint16_t selector) {
CFDictionaryRef innerDict;
CFNumberRef numType, numSelector;
// not well documented, but fixed-size arrays don't support __block either (VLAs are documented as being unsupported)
const void *keys[2], *values[2];
keys[0] = kCTFontFeatureTypeIdentifierKey;
keys[1] = kCTFontFeatureSelectorIdentifierKey;
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(outerArray, innerDict);
CFRelease(innerDict);
CFRelease(numSelector);
CFRelease(numType);
});
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)
{
CFMutableArrayRef outerArray = (CFMutableArrayRef) data;
CFDictionaryRef innerDict;
// TODO rename this to tagstr (and all the other variables likewise...)
CFStringRef strTag;
CFNumberRef numValue;
char tagcstr[5];
const void *keys[2], *values[2];
tagcstr[0] = a;
tagcstr[1] = b;
tagcstr[2] = c;
tagcstr[3] = d;
tagcstr[4] = '\0';
keys[0] = *FUTURE_kCTFontOpenTypeFeatureTag;
keys[1] = *FUTURE_kCTFontOpenTypeFeatureValue;
strTag = CFStringCreateWithCString(NULL, tagcstr, kCFStringEncodingUTF8);
if (strTag == NULL) {
// TODO
}
numValue = CFNumberCreate(NULL, kCFNumberSInt32Type,
(const SInt32 *) (&value));
values[0] = strTag;
values[1] = numValue;
innerDict = CFDictionaryCreate(NULL,
keys, values, 2,
// TODO are these correct?
&kCFCopyStringDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
if (innerDict == NULL) {
// TODO
}
CFArrayAppendValue(outerArray, innerDict);
CFRelease(innerDict);
CFRelease(numValue);
CFRelease(strTag);
return uiForEachContinue;
}
CFArrayRef otfToFeaturesArray(const uiOpenTypeFeatures *otf)
{
CFMutableArrayRef outerArray;
uiOpenTypeFeaturesForEachFunc f;
outerArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
if (outerArray == NULL) {
// TODO
}
f = otfArrayForEachAAT;
if (FUTURE_kCTFontOpenTypeFeatureTag != NULL && FUTURE_kCTFontOpenTypeFeatureValue != NULL)
f = otfArrayForEachOT;
uiOpenTypeFeaturesForEach(otf, f, outerArray);
return outerArray;
}