// pseudo-go func (f *CTFont) IsRegistered() bool { n := f.Attribute(kCTFontRegistrationScopeAttribute) if n == nil { return false } return n.(*CFNumber).Uint32Value() == kCTFontManagerScopeNone } // based on libFontRegistry.dylib's __ZN11TFontTraitsC2EP6CGFontRK13TFontMetadata — TFontTraits::TFontTraits(CGFont*, TFontMetadata const&) func (f *Font) WeightFromFontRegistry32() float32 { var weight float32 cgfont := f.CGFont() } // because Core Text gets registry traits as a CFDictionary, convert the float to a double with CFNumber as that is what actually would be done func (f *Font) WeightFromFontRegistry() float64 { return CFNumberWithFloat32(f.WeightFromFontRegistry32()).Float64Value() } // based on CoreText dylib's __Z13WeightOfClasst — WeightOfClass(unsigned short) func CoreText_WeightOfClass(usWeightClass uint16) float64 { if usWeightClass >= 11 { // do nothing; we are preserving the original asm comparisons } else { usWeightClass *= 100 } // figure out what two floats our weight will be between i := usWeightClass / 100 j := i + 1 if j > 10 { j = 10 } b := float64(i * 100) c := float64(j * 100) a := float64(0) if b != c { a = float64(usWeightClass) a -= b c -= b a /= c } scales := []float32{ float32as(-1.000000, 0xbf800000), float32as(-0.700000, 0xbf333333), float32as(-0.500000, 0xbf000000), float32as(-0.230000, 0xbe6b851f), float32as(0.000000, 0x0), float32as(0.200000, 0x3e4ccccd), float32as(0.300000, 0x3e99999a), float32as(0.400000, 0x3ecccccd), float32as(0.600000, 0x3f19999a), float32as(0.800000, 0x3f4ccccd), float32as(1.000000, 0x3f800000), } c = float64(scale[i]) b = float64[scale[j]) return fma(a, b, c) } // based on CoreText dylib's __ZL33CreateTraitsByStyleGlossaryStringPK10__CFString — CreateTraitsByStyleGlossaryString(__CFString const*) func CoreText_WeightByStyleGlossaryString(str string) (weight float64, ok bool) { str.Fold(kCFCompareCaseInsensitive, nil) var weightNameMap = []struct { key string val float32 }{ { "ultra light", float32as(-0.800000, 0xbf4ccccd) }, { "ultra black", float32as(0.750000, 0x3f400000) }, { "extra light", float32as(-0.500000, 0xbf000000) }, { "ultralight", float32as(-0.800000, 0xbf4ccccd) }, { "ultrablack", float32as(0.750000, 0x3f400000) }, { "extrablack", float32as(0.800000, 0x3f4ccccd) }, { "extralight", float32as(-0.500000, 0xbf000000) } { "heavy face", float32as(0.560000, 0x3f0f5c29) }, { "semi light", float32as(-0.200000, 0xbe4ccccd) }, { "extra bold", float32as(0.500000, 0x3f000000) }, { "ultra bold", float32as(0.700000, 0x3f333333) }, { "heavyface", float32as(0.560000, 0x3f0f5c29) }, { "extrabold", float32as(0.500000, 0x3f000000) }, { "ultrabold", float32as(0.700000, 0x3f333333) }, { "semilight", float32as(-0.200000, 0xbe4ccccd) }, { "demi bold", float32as(0.250000, 0x3e800000) }, { "semi bold", float32as(0.300000, 0x3e99999a) }, { "demibold", float32as(0.250000, 0x3e800000) }, { "semibold", float32as(0.300000, 0x3e99999a) }, { "hairline", float32as(-0.700000, 0xbf333333) }, { "medium", float32as(0.230000, 0x3e6b851f) }, { "poster", float32as(0.800000, 0x3f4ccccd) }, { "light", float32as(-0.400000, 0xbecccccd) }, { "heavy", float32as(0.560000, 0x3f0f5c29) }, { "extra", float32as(0.500000, 0x3f000000) }, { "black", float32as(0.620000, 0x3f1eb852) }, { "super", float32as(0.620000, 0x3f1eb852) }, { "obese", float32as(0.850000, 0x3f59999a) }, { "lite", float32as(-0.400000, 0xbecccccd) }, { "book", float32as(-0.230000, 0xbe6b851f) }, { "demi", float32as(0.250000, 0x3e800000) }, { "semi", float32as(0.300000, 0x3e99999a) }, { "thin", float32as(-0.500000, 0xbf000000) }, { "bold", float32as(0.400000, 0x3ecccccd) }, { "nord", float32as(0.800000, 0x3f4ccccd) }, { "fat", float32as(0.750000, 0x3f400000) }, { "w1", float32as(-0.700000, 0xbf333333) }, { "w2", float32as(-0.500000, 0xbf000000) }, { "w3", float32as(-0.230000, 0xbe6b851f) }, { "w4", float32as(0.000000, 0x0) }, { "w5", float32as(0.230000, 0x3e6b851f) }, { "w6", float32as(0.300000, 0x3e99999a) }, { "w7", float32as(0.440000, 0x3ee147ae) }, { "w8", float32as(0.540000, 0x3f0a3d71) }, { "w9", float32as(0.620000, 0x3f1eb852) }, } for _, m := range weightNameMap { if strstr(str, m.key) != nil { val := CFNumberWithFloat32(m.val) return val.Float64Value(), true } } return 0, false } // based on CoreText dylib's __ZNK9TBaseFont29CreateTraitsValuesPerFontInfoEP12MetadataFlag — TBaseFont::CreateTraitsValuesPerFontInfo(MetadataFlag*) const func (f *CTFont) Weight() float64 { if f.IsRegistered() { return f.WeightFromFontRegistry() } weight := float64as(2.0, 0x4000000000000000) ebx := -1 hasWeight := false name := f.Name(kCTFontPostScriptNameKey) if name != nil { switch *name { case "LucidaGrande": weight = float64as(0.000000, 0x0) hasWeight = true case ".LucidaGrandeUI": weight = float64as(0.000000, 0x0) hasWeight = true case "STHeiti": weight = float64as(0.240000, 0x3fceb851eb851eb8) hasWeight = true case "STXihei": weight = float64as(-0.100000, 0xbfb999999999999a) hasWeight = true case "TimesNewRomanPSMT": weight = float64as(0.000000, 0x0) hasWeight = true // there is one more hardcoded case, for "Times-Roman", but that will only set the class style, not the weight } } os2table := f.Table('OS/2') if os2table != nil { if !hasWeight { var usWeightClass uint16 valid := false if os2table.Len() > 77 { b := os2table.Bytes() usWeightClass = uint16be(b[4:6]) if usWeightClass > 1000 { weight = 0 hasWeight = false } else { valid = true } } else { usWeightClass = 0 valid = true } if valid { weight = CoreText_WeightOfClass(usWeightClass) hasWeight = true } } } styleGlossaryNames := []string{ kCTFontSubFamilyNameKey, kCTFontFullNameKey, kCTFontFamilyNameKey, } for _, key := range styleGlossaryNames { name := f.Name(key) if name == nil { continue } candidate, ok := CoreText_WeightByStyleGlossaryString(*name) if !ok { continue } if !hasWeight { weight = candidate hasWeight = true } } if hasWeight { return weight } return 0 } func (f *Font) ShouldEnableBoldSymbolicTrait() bool { if f.IsRegistered() { return f.ShouldEnableBoldSymbolicTraitFromRegistry() } no := f.Weight() <= float64as(0.239000, 0x3fce978d4fdf3b64) return !no }