iosxcodeuifontdescriptorctfont

How to use UIFontDescriptor when CTFeatureTypeIdentifier is not available


I use the following snippet to get the font features:

let font = UIFont.systemFont(ofSize: 16)
let features: NSArray = CTFontCopyFeatures(font)!
print("properties = \(features)")

So If I see this:

{
CTFeatureTypeExclusive = 1;
CTFeatureTypeIdentifier = 22;
CTFeatureTypeName = "Text Spacing";
CTFeatureTypeSelectors =         (
                {
        CTFeatureSelectorDefault = 1;
        CTFeatureSelectorIdentifier = 7;
        CTFeatureSelectorName = "No Change";
    },
                {
        CTFeatureSelectorIdentifier = 8;
        CTFeatureSelectorName = "No Kerning";
    }
);

I can translate that into Swift as:

 let fontDescriptorFeatureSettings = [
            [ UIFontDescriptor.FeatureKey.featureIdentifier : 22,
              UIFontDescriptor.FeatureKey.typeIdentifier : 8], ]

This successfully disables kerning for me.

In the same snippet, I see:

{
CTFeatureOpenTypeTag = cv05;
CTFeatureSampleText = I;
CTFeatureTooltipText = "\U00a9 2015-2022 Apple Inc. All rights reserved.";
CTFeatureTypeExclusive = 1;
CTFeatureTypeName = "Seriffed Capital I";
CTFeatureTypeSelectors =         (
                {
        CTFeatureOpenTypeValue = 0;
        CTFeatureSelectorDefault = 1;
        CTFeatureSelectorName = Off;
    },
                {
        CTFeatureOpenTypeValue = 1;
        CTFeatureSelectorName = On;
    }
);

How do I translate that into Swift to get a Seriffed 'I'?

The issue for me is the absence of:

CTFeatureTypeIdentifier


Solution

  • First of all, your kerning disablement code is wrong, in two ways:

    So when you say

    let fontDescriptorFeatureSettings = [
        [ 
            UIFontDescriptor.FeatureKey.featureIdentifier: 22,
            UIFontDescriptor.FeatureKey.typeIdentifier: 8,
        ],
    ]
    

    You should be saying

    let fontDescriptorFeatureSettings = [
        [ 
            UIFontDescriptor.FeatureKey.type: kTextSpacingType,
            UIFontDescriptor.FeatureKey.selector: 8,
        ],
    ]
    // I couldn't find a name for the `8` here
    

    Okay, so. To get a seriffed I, specify the kStylisticAltSixOnSelector as your kStylisticAlternativesType.

    let fontDescriptorFeatureSettings = [
        [ 
            UIFontDescriptor.FeatureKey.type: kStylisticAlternativesType,
            UIFontDescriptor.FeatureKey.selector: kStylisticAltSixOnSelector,
        ],
    ]
    

    Now, you might say, "Okay, fine, but I'm also getting some other changes I didn't necessarily want, such as the curvy ell and the slashed zero."

    That is true, but at the high level at which you are operating with UIFontDescriptor, there's nothing you can do about that. What you have found in the dictionary are individual glyph variants. The only way you can access those is by drawing your text directly with CoreText, and I don't think there's any chance you're going to want to get down to that level of text drawing. What you want to do is just pop this text into a UILabel or similar, and be done with it; in that case, turning on the alt six variant is the best you can do.