And finished integrating the new attributed string stuff on OS X.

This commit is contained in:
Pietro Gagliardi 2017-05-30 15:24:31 -04:00
parent 06becce34c
commit 01df4631f6
7 changed files with 50 additions and 45 deletions

View File

@ -60,7 +60,7 @@ static void attrClearSpec(struct attr *a)
uiFree((char *) (a->spec.Family));
break;
case uiAttributeFeatures:
uiOpenTypeFeaturesFree((uiOpenTypeFeatures *) (a->spec.Features));
uiFreeOpenTypeFeatures((uiOpenTypeFeatures *) (a->spec.Features));
break;
}
}

View File

@ -16,8 +16,6 @@ static void boolspec(uint32_t value, uint16_t type, uint16_t ifTrue, uint16_t if
// TODO double-check drawtext example to make sure all of these are used properly (I already screwed dlig up by putting clig twice instead)
void openTypeToAAT(char a, char b, char c, char d, uint32_t value, aatBlock f)
{
struct openTypeAATParams *p = (struct openTypeAATParams *) data;
switch (mkTag(a, b, c, d)) {
case mkTag('l', 'i', 'g', 'a'):
boolspec(value, kLigaturesType,
@ -55,45 +53,45 @@ void openTypeToAAT(char a, char b, char c, char d, uint32_t value, aatBlock f)
// 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
f(p, kLetterCaseType, 14);
f(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)
f(p, kNumberSpacingType, kProportionalNumbersSelector);
f(kNumberSpacingType, kProportionalNumbersSelector);
break;
case mkTag('t', 'n', 'u', 'm'):
if (value != 0)
f(p, kNumberSpacingType, kMonospacedNumbersSelector);
f(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)
f(p, kVerticalPositionType, kSuperiorsSelector);
f(kVerticalPositionType, kSuperiorsSelector);
break;
case mkTag('s', 'u', 'b', 's'):
if (value != 0)
f(p, kVerticalPositionType, kInferiorsSelector);
f(kVerticalPositionType, kInferiorsSelector);
break;
case mkTag('o', 'r', 'd', 'n'):
if (value != 0)
f(p, kVerticalPositionType, kOrdinalsSelector);
f(kVerticalPositionType, kOrdinalsSelector);
break;
case mkTag('s', 'i', 'n', 'f'):
if (value != 0)
f(p, kVerticalPositionType, kScientificInferiorsSelector);
f(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)
f(p, kFractionsType, kVerticalFractionsSelector);
f(kFractionsType, kVerticalFractionsSelector);
break;
case mkTag('f', 'r', 'a', 'c'):
if (value != 0)
f(p, kFractionsType, kDiagonalFractionsSelector);
f(kFractionsType, kDiagonalFractionsSelector);
break;
case mkTag('z', 'e', 'r', 'o'):
@ -109,57 +107,57 @@ void openTypeToAAT(char a, char b, char c, char d, uint32_t value, aatBlock f)
f);
break;
case mkTag('o', 'r', 'n', 'm'):
f(p, kOrnamentSetsType, (uint16_t) value);
f(kOrnamentSetsType, (uint16_t) value);
break;
case mkTag('a', 'a', 'l', 't'):
f(p, kCharacterAlternativesType, (uint16_t) value);
f(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)
f(p, kStyleOptionsType, kTitlingCapsSelector);
f(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)
f(p, kCharacterShapeType, kTraditionalCharactersSelector);
f(kCharacterShapeType, kTraditionalCharactersSelector);
break;
case mkTag('s', 'm', 'p', 'l'):
if (value != 0)
f(p, kCharacterShapeType, kSimplifiedCharactersSelector);
f(kCharacterShapeType, kSimplifiedCharactersSelector);
break;
case mkTag('j', 'p', '7', '8'):
if (value != 0)
f(p, kCharacterShapeType, kJIS1978CharactersSelector);
f(kCharacterShapeType, kJIS1978CharactersSelector);
break;
case mkTag('j', 'p', '8', '3'):
if (value != 0)
f(p, kCharacterShapeType, kJIS1983CharactersSelector);
f(kCharacterShapeType, kJIS1983CharactersSelector);
break;
case mkTag('j', 'p', '9', '0'):
if (value != 0)
f(p, kCharacterShapeType, kJIS1990CharactersSelector);
f(kCharacterShapeType, kJIS1990CharactersSelector);
break;
case mkTag('e', 'x', 'p', 't'):
if (value != 0)
f(p, kCharacterShapeType, kExpertCharactersSelector);
f(kCharacterShapeType, kExpertCharactersSelector);
break;
case mkTag('j', 'p', '0', '4'):
if (value != 0)
f(p, kCharacterShapeType, kJIS2004CharactersSelector);
f(kCharacterShapeType, kJIS2004CharactersSelector);
break;
case mkTag('h', 'o', 'j', 'o'):
if (value != 0)
f(p, kCharacterShapeType, kHojoCharactersSelector);
f(kCharacterShapeType, kHojoCharactersSelector);
break;
case mkTag('n', 'l', 'c', 'k'):
if (value != 0)
f(p, kCharacterShapeType, kNLCCharactersSelector);
f(kCharacterShapeType, kNLCCharactersSelector);
break;
case mkTag('t', 'n', 'a', 'm'):
if (value != 0)
f(p, kCharacterShapeType, kTraditionalNamesCharactersSelector);
f(kCharacterShapeType, kTraditionalNamesCharactersSelector);
break;
case mkTag('o', 'n', 'u', 'm'):
@ -168,15 +166,15 @@ void openTypeToAAT(char a, char b, char c, char d, uint32_t value, aatBlock f)
case mkTag('l', 'n', 'u', 'm'):
// TODO is this correct, or should we provide an else case?
if (value != 0)
f(p, kNumberCaseType, kLowerCaseNumbersSelector);
f(kNumberCaseType, kLowerCaseNumbersSelector);
break;
case mkTag('h', 'n', 'g', 'l'):
// TODO is this correct, or should we provide an else case?
if (value != 0)
f(p, kTransliterationType, kHanjaToHangulSelector);
f(kTransliterationType, kHanjaToHangulSelector);
break;
case mkTag('n', 'a', 'l', 't'):
f(p, kAnnotationType, (uint16_t) value);
f(kAnnotationType, (uint16_t) value);
break;
case mkTag('r', 'u', 'b', 'y'):
// include this for completeness
@ -370,24 +368,24 @@ void openTypeToAAT(char a, char b, char c, char d, uint32_t value, aatBlock f)
if (value != 0) {
// include this for compatibility (some fonts that come with OS X still use this!)
// TODO make it boolean?
f(p, kLetterCaseType, kSmallCapsSelector);
f(kLetterCaseType, kSmallCapsSelector);
// this is the current one
f(p, kLowerCaseType, kLowerCaseSmallCapsSelector);
f(kLowerCaseType, kLowerCaseSmallCapsSelector);
}
break;
case mkTag('p', 'c', 'a', 'p'):
if (value != 0)
f(p, kLowerCaseType, kLowerCasePetiteCapsSelector);
f(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)
f(p, kUpperCaseType, kUpperCaseSmallCapsSelector);
f(kUpperCaseType, kUpperCaseSmallCapsSelector);
break;
case mkTag('c', '2', 'p', 'c'):
if (value != 0)
f(p, kUpperCaseType, kUpperCasePetiteCapsSelector);
f(kUpperCaseType, kUpperCasePetiteCapsSelector);
break;
}
// TODO handle this properly

View File

@ -131,7 +131,8 @@ struct foreachParams {
CTFontDescriptorRef desc;
CTFontRef font;
uidesc.Family = self.family;
// TODO const-correct uiDrawFontDescriptor or change this function below
uidesc.Family = (char *) (self.family);
uidesc.Size = self.size;
uidesc.Weight = self.weight;
uidesc.Italic = self.italic;
@ -170,7 +171,7 @@ static void adjustFontInRange(struct foreachParams *p, size_t start, size_t end,
for (i = start; i < end; i++) {
n = [NSNumber numberWithInteger:i];
v = (combinedFontAttr *) [p->combinedFontAttrs objectForKey:n];
cfa = (combinedFontAttr *) [p->combinedFontAttrs objectForKey:n];
adj(cfa);
}
}
@ -329,7 +330,7 @@ static BOOL cfaIsEqual(combinedFontAttr *a, combinedFontAttr *b)
static void applyAndFreeFontAttributes(struct foreachParams *p)
{
CFIndex i;
CFIndex i, n;
combinedFontAttr *cfa, *cfab;
CTFontRef defaultFont;
CTFontRef font;
@ -349,6 +350,7 @@ static void applyAndFreeFontAttributes(struct foreachParams *p)
for (i = 0; i < n; i++) {
NSNumber *nn;
// TODO use NSValue or some other method of NSNumber
nn = [NSNumber numberWithInteger:i];
cfab = (combinedFontAttr *) [p->combinedFontAttrs objectForKey:nn];
if (cfaIsEqual(cfa, cfab))
@ -357,6 +359,7 @@ static void applyAndFreeFontAttributes(struct foreachParams *p)
// the font has changed; write out the old one
range.length = i - range.location;
if (cfa == nil) {
// TODO this isn't necessary because of default font shenanigans below
font = defaultFont;
CFRetain(font);
} else
@ -371,6 +374,7 @@ static void applyAndFreeFontAttributes(struct foreachParams *p)
// and finally, write out the last range
range.length = i - range.location;
if (cfa == nil) {
// TODO likewise
font = defaultFont;
CFRetain(font);
} else
@ -414,7 +418,6 @@ CFAttributedStringRef attrstrToCoreFoundation(uiDrawTextLayoutParams *p, NSArray
CFAttributedStringRef base;
CFMutableAttributedStringRef mas;
struct foreachParams fep;
struct fontParams ffp;
cfstr = CFStringCreateWithCharacters(NULL, attrstrUTF16(p->String), attrstrUTF16Len(p->String));
if (cfstr == NULL) {
@ -426,11 +429,12 @@ CFAttributedStringRef attrstrToCoreFoundation(uiDrawTextLayoutParams *p, NSArray
if (defaultAttrs == NULL) {
// TODO
}
memset(&ffp, 0, sizeof (struct fontParams));
#if 0 /* TODO */
ffp.desc = *(p->DefaultFont);
defaultCTFont = fontdescToCTFont(&ffp);
CFDictionaryAddValue(defaultAttrs, kCTFontAttributeName, defaultCTFont);
CFRelease(defaultCTFont);
#endif
ps = mkParagraphStyle(p);
CFDictionaryAddValue(defaultAttrs, kCTParagraphStyleAttributeName, ps);
CFRelease(ps);

View File

@ -258,8 +258,9 @@ CTFontDescriptorRef fontdescToCTFontDescriptor(uiDrawFontDescriptor *fd)
CTFontDescriptorRef fontdescAppendFeatures(CTFontDescriptorRef desc, const uiOpenTypeFeatures *otf)
{
CTFontDescriptorRef new;
CFMutableArrayRef featuresArray;
CFArrayRef featuresArray;
CFDictionaryRef attrs;
const void *keys[1], *values[1];
featuresArray = otfToFeaturesArray(otf);
keys[0] = kCTFontFeatureSettingsAttribute;

View File

@ -93,14 +93,15 @@ int uiOpenTypeFeaturesEqual(const uiOpenTypeFeatures *a, const uiOpenTypeFeature
static int otfArrayForEach(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;
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,
@ -115,7 +116,7 @@ static int otfArrayForEach(char a, char b, char c, char d, uint32_t value, void
if (innerDict == NULL) {
// TODO
}
CFArrayAppendValue(p->outerArray, innerDict);
CFArrayAppendValue(outerArray, innerDict);
CFRelease(innerDict);
CFRelease(numSelector);
CFRelease(numType);

View File

@ -170,7 +170,7 @@ static void setupAttributedString(void)
spec.A = 0.75;
uiAttributedStringSetAttribute(attrstr, &spec, start + 12, end);
spec.Type = uiAttributeFamily;
spec.Value = "Helvetica";
spec.Family = "Helvetica";
uiAttributedStringSetAttribute(attrstr, &spec, start + 8, end - 1);
spec.Type = uiAttributeBackground;
spec.R = 1.0;
@ -245,7 +245,7 @@ static void setupAttributedString(void)
end = start + strlen(next);
uiAttributedStringAppendUnattributed(attrstr, next);
spec.Type = uiAttributeFeatures;
spec.Value = otf;
spec.Features = otf;
uiAttributedStringSetAttribute(attrstr, &spec, start, end);
uiAttributedStringAppendUnattributed(attrstr, ")");

View File

@ -256,6 +256,7 @@ _UI_EXTERN void uiDrawCaret(uiDrawContext *c, double x, double y, uiDrawTextLayo
typedef struct uiFontButton uiFontButton;
#define uiFontButton(this) ((uiFontButton *) (this))
// TODO have a function that sets an entire font descriptor to a range in a uiAttributedString at once?
_UI_EXTERN void uiFontButtonFont(uiFontButton *b, uiDrawFontDescriptor *desc);
// TOOD SetFont, mechanics
_UI_EXTERN void uiFontButtonOnChanged(uiFontButton *b, void (*f)(uiFontButton *, void *), void *data);