Option Sets intersections in Swift

263 views Asked by At

Now I read Apple documentation about Core Text and I have one problem in understanding:

CTFontSymbolicTraits conforms to OptionSet. And CTFontStylisticClass can be obtained via classMaskTrait option in CTFontStylisticClass.

Am I understand right that classMaskTrait option can includes all CTFontStylisticClass-options?. For example, if I want to detect sansSerifClass option in CTFontStylisticClass:

CTFontStylisticClass(rawValue: CTFontGetSymbolicTraits(font).rawValue).contains(.sansSerifClass)

is it right example checking?

1

There are 1 answers

0
rob mayoff On

To understand these constants, let's look at the CTFontStylisticClass documentation:

The class values are bundled in the upper four bits of the CTFontSymbolicTraits and can be obtained via kCTFontClassMaskTrait.

To verify, let's look at the kCTFontClassMaskTrait documentation. If you set the language to Objective-C, the documentation shows the definitions of kCTFontClassMaskTrait:

kCTFontClassMaskTrait = kCTFontTraitClassMask

So it's just defined as another constant, which has all the same words in a different order. Ha ha, Apple, you're hilarious.

Okay, let's look at the kCTFontTraitClassMask documentation. Again, if you set the language to Objective-C, you can see the definition of the constant:

kCTFontTraitClassMask = (15U << kCTFontClassMaskShift)

Indeed, 15U is four consecutive 1 bits, and it's shifted left by some amount. This is typical of a “mask”: it defines a subset of the bits in a binary word.

To convert a CTFontSymbolicTraits to a CTFontStylisticClass, we need to use the mask to select just those bits from the CTFontSymbolicTraits raw value, and use the result as the raw value of a CTFontStylisticClass. We can do the selection by using the bitwise operator &, or by using the OptionSet method intersection.

What we really want, in Swift, is a method on CTFontSymbolicTraits that extracts a CTFontStylisticClass. So let's write an extension:

extension CTFontSymbolicTraits {
    var stylisticClass: CTFontStylisticClass {
        return CTFontStylisticClass(rawValue: self.intersection(.classMaskTrait).rawValue)
    }
}

Let's test it:

import CoreText
import Foundation

extension CTFontSymbolicTraits {
    var stylisticClass: CTFontStylisticClass {
        return CTFontStylisticClass(rawValue: self.intersection(.classMaskTrait).rawValue)
    }
}

func checkSansSerifness(fontName: String) {
    let font = CTFontCreateWithName(fontName as CFString, 12, nil)
    let fullName = CTFontCopyName(font, kCTFontFullNameKey)!
    if CTFontGetSymbolicTraits(font).stylisticClass.contains(.sansSerifClass) {
        print("\(fullName) is sans serif.")
    } else {
        print("\(fullName) is not sans serif.")
    }
}

checkSansSerifness(fontName: "Helvetica")
checkSansSerifness(fontName: "Times New Roman")

Output:

Helvetica is sans serif.
Times New Roman is not sans serif.