diff --git a/doc/export/ctweights b/doc/export/ctweights new file mode 100644 index 00000000..31508150 --- /dev/null +++ b/doc/export/ctweights @@ -0,0 +1,218 @@ +// 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 +}