refactor(重构提升): 优化性能
build.yaml / build (push) Successful in 35s

This commit is contained in:
2026-07-10 09:19:20 +08:00
parent a1e6a86134
commit f1a1f2e151
4 changed files with 90 additions and 66 deletions
+58 -35
View File
@@ -146,13 +146,13 @@ func (fsys *FontFS) matchStyle(pattern string, bold, italic bool) []string {
// 入参: patterns 匹配模式列表, bold 是否粗体, italic 是否斜体 // 入参: patterns 匹配模式列表, bold 是否粗体, italic 是否斜体
// 返回: []string 字体文件列表 // 返回: []string 字体文件列表
func (fsys *FontFS) matchPatternsStyle(patterns []string, bold, italic bool) []string { func (fsys *FontFS) matchPatternsStyle(patterns []string, bold, italic bool) []string {
var matches []fontFileMatch
seen := make(map[string]int)
files := fontFileCandidates(fsys.names, path.Base) files := fontFileCandidates(fsys.names, path.Base)
matches := make([]fontFileMatch, 0, len(files))
seen := make(map[string]int, len(files))
for _, matcher := range newFontPatternMatchers(patterns) { for _, matcher := range newFontPatternMatchers(patterns) {
for _, file := range files { for _, file := range files {
rank := matcher.rank(file.base) rank := matcher.rankCandidate(file)
appendFontFileMatch(&matches, seen, matcher.pattern, file.name, rank, bold, italic) appendFontFileMatch(&matches, seen, matcher, file, rank, bold, italic)
} }
} }
sortFontFileMatches(matches) sortFontFileMatches(matches)
@@ -210,8 +210,11 @@ func matchFontPatternRank(pattern, name string) int {
} }
type fontFileCandidate struct { type fontFileCandidate struct {
name string name string
base string base string
lowerBase string
normalized string
fold string
} }
// fontFileCandidates 筛选字体文件候选 // fontFileCandidates 筛选字体文件候选
@@ -221,7 +224,14 @@ func fontFileCandidates(names []string, base func(string) string) []fontFileCand
files := make([]fontFileCandidate, 0, len(names)) files := make([]fontFileCandidate, 0, len(names))
for _, name := range names { for _, name := range names {
if isFontFileName(name) { if isFontFileName(name) {
files = append(files, fontFileCandidate{name: name, base: base(name)}) baseName := base(name)
files = append(files, fontFileCandidate{
name: name,
base: baseName,
lowerBase: strings.ToLower(baseName),
normalized: fontNormalizeName(baseName),
fold: strings.ToLower(name),
})
} }
} }
return files return files
@@ -269,16 +279,26 @@ func newFontPatternMatchers(patterns []string) []fontPatternMatcher {
// 入参: name 字体文件名 // 入参: name 字体文件名
// 返回: int 匹配等级 // 返回: int 匹配等级
func (m fontPatternMatcher) rank(name string) int { func (m fontPatternMatcher) rank(name string) int {
rawName := name return m.rankCandidate(fontFileCandidate{
exactPath, _ := path.Match(m.pattern, name) base: name,
lowerPath, _ := path.Match(m.lowerPattern, strings.ToLower(name)) lowerBase: strings.ToLower(name),
normalized: fontNormalizeName(name),
})
}
// rankCandidate 获取字体文件候选匹配等级
// 入参: file 字体文件候选
// 返回: int 匹配等级
func (m fontPatternMatcher) rankCandidate(file fontFileCandidate) int {
exactPath, _ := path.Match(m.pattern, file.base)
lowerPath, _ := path.Match(m.lowerPattern, file.lowerBase)
if m.stem == "" { if m.stem == "" {
if exactPath || lowerPath { if exactPath || lowerPath {
return fontMatchFuzzy return fontMatchFuzzy
} }
return fontMatchNone return fontMatchNone
} }
name = fontNormalizeName(name) name := file.normalized
if name == m.stem { if name == m.stem {
return fontMatchExact return fontMatchExact
} }
@@ -287,7 +307,7 @@ func (m fontPatternMatcher) rank(name string) int {
return fontMatchExact return fontMatchExact
} }
} }
if fontFileKnownStyleSuffix(m.styleSuffix(rawName)) { if fontFileKnownStyleSuffix(m.styleSuffixNormalized(name)) {
return fontMatchExact return fontMatchExact
} }
if strings.HasPrefix(name, m.stem) { if strings.HasPrefix(name, m.stem) {
@@ -309,20 +329,19 @@ func (m fontPatternMatcher) rank(name string) int {
return fontMatchNone return fontMatchNone
} }
// styleSuffix 获取字体文件样式后缀 // styleSuffixNormalized 获取规范字体名称的样式后缀
// 入参: name 字体文件名 // 入参: name 规范字体名称
// 返回: string 样式后缀 // 返回: string 样式后缀
func (m fontPatternMatcher) styleSuffix(name string) string { func (m fontPatternMatcher) styleSuffixNormalized(name string) string {
key := fontNormalizeName(name) if m.stem == "" || name == "" {
if m.stem == "" || key == "" {
return "" return ""
} }
if strings.HasPrefix(key, m.stem) { if strings.HasPrefix(name, m.stem) {
return strings.TrimPrefix(key, m.stem) return strings.TrimPrefix(name, m.stem)
} }
for _, alias := range m.aliases { for _, alias := range m.aliases {
if strings.HasPrefix(key, alias) { if strings.HasPrefix(name, alias) {
return strings.TrimPrefix(key, alias) return strings.TrimPrefix(name, alias)
} }
} }
return "" return ""
@@ -336,25 +355,24 @@ type fontFileMatch struct {
} }
// appendFontFileMatch 追加字体文件匹配结果 // appendFontFileMatch 追加字体文件匹配结果
// 入参: matches 匹配结果, seen 已匹配文件, pattern 匹配模式, name 字体文件, rank 匹配等级, bold 是否粗体, italic 是否斜体 // 入参: matches 匹配结果, seen 已匹配文件, matcher 匹配器, file 字体文件候选, rank 匹配等级, bold 是否粗体, italic 是否斜体
func appendFontFileMatch(matches *[]fontFileMatch, seen map[string]int, pattern, name string, rank int, bold, italic bool) { func appendFontFileMatch(matches *[]fontFileMatch, seen map[string]int, matcher fontPatternMatcher, file fontFileCandidate, rank int, bold, italic bool) {
if rank == fontMatchNone || !isFontFileName(name) { if rank == fontMatchNone {
return return
} }
key := strings.ToLower(name)
next := fontFileMatch{ next := fontFileMatch{
name: name, name: file.name,
rank: rank, rank: rank,
styleRank: fontFileStyleRank(pattern, name, bold, italic), styleRank: fontFileStyleRank(matcher.styleSuffixNormalized(file.normalized), bold, italic),
sortName: strings.ToLower(path.Base(name)), sortName: file.lowerBase,
} }
if index, ok := seen[key]; ok { if index, ok := seen[file.fold]; ok {
if fontFileMatchLess(next, (*matches)[index]) { if fontFileMatchLess(next, (*matches)[index]) {
(*matches)[index] = next (*matches)[index] = next
} }
return return
} }
seen[key] = len(*matches) seen[file.fold] = len(*matches)
*matches = append(*matches, next) *matches = append(*matches, next)
} }
@@ -391,10 +409,10 @@ func fontFileMatchNames(matches []fontFileMatch) []string {
} }
// fontFileStyleRank 获取字体文件样式匹配等级 // fontFileStyleRank 获取字体文件样式匹配等级
// 入参: pattern 匹配模式, name 字体文件名, bold 是否粗体, italic 是否斜体 // 入参: suffix 样式后缀, bold 是否粗体, italic 是否斜体
// 返回: int 样式匹配等级 // 返回: int 样式匹配等级
func fontFileStyleRank(pattern, name string, bold, italic bool) int { func fontFileStyleRank(suffix string, bold, italic bool) int {
fileBold, fileItalic := fontFileStyle(pattern, name) fileBold, fileItalic := fontFileStyleFromSuffix(suffix)
rank := 0 rank := 0
if fileBold != bold { if fileBold != bold {
rank += 2 rank += 2
@@ -402,7 +420,6 @@ func fontFileStyleRank(pattern, name string, bold, italic bool) int {
if fileItalic != italic { if fileItalic != italic {
rank += 2 rank += 2
} }
suffix := fontFileStyleSuffix(pattern, name)
if !bold && !italic && !fileBold && !fileItalic && suffix != "" && !fontFileRegularSuffix(suffix) { if !bold && !italic && !fileBold && !fileItalic && suffix != "" && !fontFileRegularSuffix(suffix) {
rank++ rank++
} }
@@ -413,7 +430,13 @@ func fontFileStyleRank(pattern, name string, bold, italic bool) int {
// 入参: pattern 匹配模式, name 字体文件名 // 入参: pattern 匹配模式, name 字体文件名
// 返回: bool 是否粗体, bool 是否斜体 // 返回: bool 是否粗体, bool 是否斜体
func fontFileStyle(pattern, name string) (bool, bool) { func fontFileStyle(pattern, name string) (bool, bool) {
suffix := fontFileStyleSuffix(pattern, name) return fontFileStyleFromSuffix(fontFileStyleSuffix(pattern, name))
}
// fontFileStyleFromSuffix 获取样式后缀对应的字体样式
// 入参: suffix 样式后缀
// 返回: bool 是否粗体, bool 是否斜体
func fontFileStyleFromSuffix(suffix string) (bool, bool) {
bold := suffix == "b" || bold := suffix == "b" ||
suffix == "bd" || suffix == "bd" ||
suffix == "bold" || suffix == "bold" ||
+4 -4
View File
@@ -225,14 +225,14 @@ func fontFSMatches(fsys fs.FS, patterns []string) []string {
// 入参: fsys 字体文件系统, patterns 匹配模式列表, bold 是否粗体, italic 是否斜体 // 入参: fsys 字体文件系统, patterns 匹配模式列表, bold 是否粗体, italic 是否斜体
// 返回: []string 字体文件列表 // 返回: []string 字体文件列表
func fontFSMatchesStyle(fsys fs.FS, patterns []string, bold, italic bool) []string { func fontFSMatchesStyle(fsys fs.FS, patterns []string, bold, italic bool) []string {
var matches []fontFileMatch
seen := make(map[string]int)
names, _ := fs.Glob(fsys, "*") names, _ := fs.Glob(fsys, "*")
candidates := fontFileCandidates(names, path.Base) candidates := fontFileCandidates(names, path.Base)
matches := make([]fontFileMatch, 0, len(candidates))
seen := make(map[string]int, len(candidates))
for _, matcher := range newFontPatternMatchers(patterns) { for _, matcher := range newFontPatternMatchers(patterns) {
for _, file := range candidates { for _, file := range candidates {
rank := matcher.rank(file.base) rank := matcher.rankCandidate(file)
appendFontFileMatch(&matches, seen, matcher.pattern, file.name, rank, bold, italic) appendFontFileMatch(&matches, seen, matcher, file, rank, bold, italic)
} }
} }
sortFontFileMatches(matches) sortFontFileMatches(matches)
+4 -4
View File
@@ -159,14 +159,14 @@ func (r *Renderer) loadFont(fontID string) *canvas.FontFamily {
// 入参: dir 目录, patterns 模式列表, bold 是否粗体, italic 是否斜体 // 入参: dir 目录, patterns 模式列表, bold 是否粗体, italic 是否斜体
// 返回: []string 文件列表 // 返回: []string 文件列表
func (r *Renderer) matchFontFiles(dir string, patterns []string, bold, italic bool) []string { func (r *Renderer) matchFontFiles(dir string, patterns []string, bold, italic bool) []string {
var matches []fontFileMatch
index := make(map[string]int)
files, _ := filepath.Glob(filepath.Join(dir, "*")) files, _ := filepath.Glob(filepath.Join(dir, "*"))
candidates := fontFileCandidates(files, filepath.Base) candidates := fontFileCandidates(files, filepath.Base)
matches := make([]fontFileMatch, 0, len(candidates))
index := make(map[string]int, len(candidates))
for _, matcher := range newFontPatternMatchers(patterns) { for _, matcher := range newFontPatternMatchers(patterns) {
for _, file := range candidates { for _, file := range candidates {
rank := matcher.rank(file.base) rank := matcher.rankCandidate(file)
appendFontFileMatch(&matches, index, matcher.pattern, file.name, rank, bold, italic) appendFontFileMatch(&matches, index, matcher, file, rank, bold, italic)
} }
} }
sortFontFileMatches(matches) sortFontFileMatches(matches)
+24 -23
View File
@@ -55,7 +55,7 @@ func (r *Renderer) textObjectGlyphTransforms(fontID string, text TextObject) map
if fontID == "" || len(text.CGTransform) == 0 { if fontID == "" || len(text.CGTransform) == 0 {
return nil return nil
} }
result := make(map[int]textGlyphTransform) result := make(map[int]textGlyphTransform, len(text.CGTransform))
for _, transform := range text.CGTransform { for _, transform := range text.CGTransform {
ids := parseInts(transform.Glyphs) ids := parseInts(transform.Glyphs)
glyphCount := len(ids) glyphCount := len(ids)
@@ -69,9 +69,9 @@ func (r *Renderer) textObjectGlyphTransforms(fontID string, text TextObject) map
if codeCount <= 0 { if codeCount <= 0 {
codeCount = 1 codeCount = 1
} }
glyphs := make([]textGlyph, 0, glyphCount) glyphs := make([]textGlyph, glyphCount)
for i := 0; i < glyphCount; i++ { for i := range glyphs {
glyphs = append(glyphs, r.textGlyphFromID(fontID, ids[i])) glyphs[i] = r.textGlyphFromID(fontID, ids[i])
} }
result[transform.CodePosition] = textGlyphTransform{ result[transform.CodePosition] = textGlyphTransform{
CodeCount: codeCount, CodeCount: codeCount,
@@ -108,9 +108,9 @@ func textCodeGlyphs(runes []rune, transforms map[int]textGlyphTransform, codeOff
// 入参: runes 文本字符 // 入参: runes 文本字符
// 返回: []textGlyph 绘制字形列表 // 返回: []textGlyph 绘制字形列表
func textRuneGlyphs(runes []rune) []textGlyph { func textRuneGlyphs(runes []rune) []textGlyph {
glyphs := make([]textGlyph, 0, len(runes)) glyphs := make([]textGlyph, len(runes))
for _, r := range runes { for i, r := range runes {
glyphs = append(glyphs, textGlyph{Text: string(r), GlyphID: -1}) glyphs[i] = textGlyph{Text: string(r), GlyphID: -1}
} }
return glyphs return glyphs
} }
@@ -208,32 +208,33 @@ func (r *Renderer) fontGlyphRune(fontID string, glyphID int) (rune, bool) {
// 入参: indexStr 索引字符串, fontID 字体ID // 入参: indexStr 索引字符串, fontID 字体ID
// 返回: []rune 字形列表 // 返回: []rune 字形列表
func (r *Renderer) parseIndexRunes(indexStr string, fontID string) []rune { func (r *Renderer) parseIndexRunes(indexStr string, fontID string) []rune {
var gids []int
parts := strings.Fields(indexStr) parts := strings.Fields(indexStr)
result := make([]rune, 0, len(parts))
for _, p := range parts { for _, p := range parts {
if strings.Contains(p, "-") { if startText, endText, ok := strings.Cut(p, "-"); ok {
sub := strings.Split(p, "-") if !strings.Contains(endText, "-") {
if len(sub) == 2 { start, _ := strconv.Atoi(startText)
start, _ := strconv.Atoi(sub[0]) end, _ := strconv.Atoi(endText)
end, _ := strconv.Atoi(sub[1])
for k := start; k <= end; k++ { for k := start; k <= end; k++ {
gids = append(gids, k) result = append(result, r.textIndexRune(fontID, k))
} }
} }
} else { } else {
val, _ := strconv.Atoi(p) val, _ := strconv.Atoi(p)
gids = append(gids, val) result = append(result, r.textIndexRune(fontID, val))
} }
} }
var res []rune return result
for _, gid := range gids { }
if rVal, ok := r.fontGlyphRune(fontID, gid); ok {
res = append(res, rVal) // textIndexRune 获取索引字形对应的字符
continue // 入参: fontID 字体ID, glyphID 字形ID或CID
} // 返回: rune 字符
res = append(res, rune(gid)) func (r *Renderer) textIndexRune(fontID string, glyphID int) rune {
if mapped, ok := r.fontGlyphRune(fontID, glyphID); ok {
return mapped
} }
return res return rune(glyphID)
} }
// textGlyphAdvanceLimit 获取显式字形推进宽度 // textGlyphAdvanceLimit 获取显式字形推进宽度