1717package util
1818
1919import (
20+ "encoding/binary"
2021 "errors"
2122 "os"
2223 "sort"
@@ -74,8 +75,7 @@ func loadFonts() (ret []*Font) {
7475 //LogInfof("[%s] [%s]", fontPath, family)
7576 }
7677 } else if strings .HasSuffix (strings .ToLower (fontPath ), ".otf" ) || strings .HasSuffix (strings .ToLower (fontPath ), ".ttf" ) {
77- f := parseTTFFontFamily (fontPath )
78- if nil != f {
78+ for _ , f := range parseTTFFontFamily (fontPath ) {
7979 if existFont (f , ret ) {
8080 continue
8181 }
@@ -114,15 +114,12 @@ func parseTTCFontFamily(fontPath string) (ret []*Font) {
114114 }
115115
116116 for _ , f := range fonts {
117- font := parseFont (f )
118- if nil != font {
119- ret = append (ret , font )
120- }
117+ ret = append (ret , parseFont (f )... )
121118 }
122119 return
123120}
124121
125- func parseTTFFontFamily (fontPath string ) * Font {
122+ func parseTTFFontFamily (fontPath string ) ( ret [] * Font ) {
126123 defer logging .Recover ()
127124
128125 fontFile , err := os .Open (fontPath )
@@ -140,9 +137,76 @@ func parseTTFFontFamily(fontPath string) *Font {
140137 return parseFont (font )
141138}
142139
143- func parseFont (font * sfnt.Font ) * Font {
144- ret , _ := parseFontInfo (font )
145- return ret
140+ func parseFont (font * sfnt.Font ) (ret []* Font ) {
141+ defaultFont , err := parseFontInfo (font )
142+ if err != nil {
143+ return nil
144+ }
145+ ret = append (ret , defaultFont )
146+ ret = append (ret , parseFontVariations (font , defaultFont .Family )... )
147+ return
148+ }
149+
150+ func parseFontVariations (font * sfnt.Font , family string ) (ret []* Font ) {
151+ defer logging .Recover ()
152+
153+ // 可变字体通过 fvar 表声明字重等可变轴,named instances 提供了命名的字重实例
154+ table , err := font .Table (sfnt .MustNamedTag ("fvar" ))
155+ if err != nil {
156+ return nil
157+ }
158+ buf := table .Bytes ()
159+ if len (buf ) < 16 {
160+ return nil
161+ }
162+ axesArrayOffset := int (binary .BigEndian .Uint16 (buf [4 :6 ]))
163+ axisCount := int (binary .BigEndian .Uint16 (buf [8 :10 ]))
164+ axisSize := int (binary .BigEndian .Uint16 (buf [10 :12 ]))
165+ instanceCount := int (binary .BigEndian .Uint16 (buf [12 :14 ]))
166+ instanceSize := int (binary .BigEndian .Uint16 (buf [14 :16 ]))
167+ if axisSize < 20 || instanceSize < 4 + axisCount * 4 || len (buf ) < axesArrayOffset + axisCount * axisSize + instanceCount * instanceSize {
168+ return nil
169+ }
170+
171+ // 找到 wght 轴在实例坐标中的位置
172+ wghtAxisIndex := - 1
173+ for i := 0 ; i < axisCount ; i ++ {
174+ base := axesArrayOffset + i * axisSize
175+ if "wght" == string (buf [base :base + 4 ]) {
176+ wghtAxisIndex = i
177+ break
178+ }
179+ }
180+ if wghtAxisIndex < 0 {
181+ return nil
182+ }
183+
184+ t , err := font .NameTable ()
185+ if err != nil {
186+ return nil
187+ }
188+ entries := t .List ()
189+ instancesBase := axesArrayOffset + axisCount * axisSize
190+ for i := 0 ; i < instanceCount ; i ++ {
191+ base := instancesBase + i * instanceSize
192+ subfamilyNameID := binary .BigEndian .Uint16 (buf [base : base + 2 ])
193+ // wght 坐标是 16.16 定点数,取整后即为 CSS font-weight
194+ weight := int (float64 (int32 (binary .BigEndian .Uint32 (buf [base + 4 + wghtAxisIndex * 4 :base + 8 + wghtAxisIndex * 4 ])))/ 65536 + 0.5 )
195+ if weight < 1 || 1000 < weight {
196+ continue
197+ }
198+ subfamily := selectFontName (entries , sfnt .NameID (subfamilyNameID ))
199+ if "" == subfamily {
200+ continue
201+ }
202+
203+ displayName := family
204+ if ! strings .EqualFold (subfamily , "Regular" ) {
205+ displayName = family + " " + subfamily
206+ }
207+ ret = append (ret , & Font {Family : family , Weight : weight , DisplayName : displayName })
208+ }
209+ return
146210}
147211
148212func parseFontInfo (font * sfnt.Font ) (* Font , error ) {
0 commit comments