From f1a1f2e15178f4889aa581abed6be4ac82c92dca Mon Sep 17 00:00:00 2001 From: xiaoqidun Date: Fri, 10 Jul 2026 09:19:20 +0800 Subject: [PATCH] =?UTF-8?q?refactor(=E9=87=8D=E6=9E=84=E6=8F=90=E5=8D=87):?= =?UTF-8?q?=20=E4=BC=98=E5=8C=96=E6=80=A7=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ofdgo_font_fs.go | 93 +++++++++++++++++++++++++++----------------- ofdgo_font_info.go | 8 ++-- ofdgo_font_loader.go | 8 ++-- ofdgo_text.go | 47 +++++++++++----------- 4 files changed, 90 insertions(+), 66 deletions(-) diff --git a/ofdgo_font_fs.go b/ofdgo_font_fs.go index ee15f11..b42cb6a 100644 --- a/ofdgo_font_fs.go +++ b/ofdgo_font_fs.go @@ -146,13 +146,13 @@ func (fsys *FontFS) matchStyle(pattern string, bold, italic bool) []string { // 入参: patterns 匹配模式列表, bold 是否粗体, italic 是否斜体 // 返回: []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) + matches := make([]fontFileMatch, 0, len(files)) + seen := make(map[string]int, len(files)) for _, matcher := range newFontPatternMatchers(patterns) { for _, file := range files { - rank := matcher.rank(file.base) - appendFontFileMatch(&matches, seen, matcher.pattern, file.name, rank, bold, italic) + rank := matcher.rankCandidate(file) + appendFontFileMatch(&matches, seen, matcher, file, rank, bold, italic) } } sortFontFileMatches(matches) @@ -210,8 +210,11 @@ func matchFontPatternRank(pattern, name string) int { } type fontFileCandidate struct { - name string - base string + name string + base string + lowerBase string + normalized string + fold string } // fontFileCandidates 筛选字体文件候选 @@ -221,7 +224,14 @@ func fontFileCandidates(names []string, base func(string) string) []fontFileCand files := make([]fontFileCandidate, 0, len(names)) for _, name := range names { 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 @@ -269,16 +279,26 @@ func newFontPatternMatchers(patterns []string) []fontPatternMatcher { // 入参: name 字体文件名 // 返回: int 匹配等级 func (m fontPatternMatcher) rank(name string) int { - rawName := name - exactPath, _ := path.Match(m.pattern, name) - lowerPath, _ := path.Match(m.lowerPattern, strings.ToLower(name)) + return m.rankCandidate(fontFileCandidate{ + base: 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 exactPath || lowerPath { return fontMatchFuzzy } return fontMatchNone } - name = fontNormalizeName(name) + name := file.normalized if name == m.stem { return fontMatchExact } @@ -287,7 +307,7 @@ func (m fontPatternMatcher) rank(name string) int { return fontMatchExact } } - if fontFileKnownStyleSuffix(m.styleSuffix(rawName)) { + if fontFileKnownStyleSuffix(m.styleSuffixNormalized(name)) { return fontMatchExact } if strings.HasPrefix(name, m.stem) { @@ -309,20 +329,19 @@ func (m fontPatternMatcher) rank(name string) int { return fontMatchNone } -// styleSuffix 获取字体文件样式后缀 -// 入参: name 字体文件名 +// styleSuffixNormalized 获取规范字体名称的样式后缀 +// 入参: name 规范字体名称 // 返回: string 样式后缀 -func (m fontPatternMatcher) styleSuffix(name string) string { - key := fontNormalizeName(name) - if m.stem == "" || key == "" { +func (m fontPatternMatcher) styleSuffixNormalized(name string) string { + if m.stem == "" || name == "" { return "" } - if strings.HasPrefix(key, m.stem) { - return strings.TrimPrefix(key, m.stem) + if strings.HasPrefix(name, m.stem) { + return strings.TrimPrefix(name, m.stem) } for _, alias := range m.aliases { - if strings.HasPrefix(key, alias) { - return strings.TrimPrefix(key, alias) + if strings.HasPrefix(name, alias) { + return strings.TrimPrefix(name, alias) } } return "" @@ -336,25 +355,24 @@ type fontFileMatch struct { } // appendFontFileMatch 追加字体文件匹配结果 -// 入参: matches 匹配结果, seen 已匹配文件, pattern 匹配模式, name 字体文件名, rank 匹配等级, bold 是否粗体, italic 是否斜体 -func appendFontFileMatch(matches *[]fontFileMatch, seen map[string]int, pattern, name string, rank int, bold, italic bool) { - if rank == fontMatchNone || !isFontFileName(name) { +// 入参: matches 匹配结果, seen 已匹配文件, matcher 匹配器, file 字体文件候选, rank 匹配等级, bold 是否粗体, italic 是否斜体 +func appendFontFileMatch(matches *[]fontFileMatch, seen map[string]int, matcher fontPatternMatcher, file fontFileCandidate, rank int, bold, italic bool) { + if rank == fontMatchNone { return } - key := strings.ToLower(name) next := fontFileMatch{ - name: name, + name: file.name, rank: rank, - styleRank: fontFileStyleRank(pattern, name, bold, italic), - sortName: strings.ToLower(path.Base(name)), + styleRank: fontFileStyleRank(matcher.styleSuffixNormalized(file.normalized), bold, italic), + sortName: file.lowerBase, } - if index, ok := seen[key]; ok { + if index, ok := seen[file.fold]; ok { if fontFileMatchLess(next, (*matches)[index]) { (*matches)[index] = next } return } - seen[key] = len(*matches) + seen[file.fold] = len(*matches) *matches = append(*matches, next) } @@ -391,10 +409,10 @@ func fontFileMatchNames(matches []fontFileMatch) []string { } // fontFileStyleRank 获取字体文件样式匹配等级 -// 入参: pattern 匹配模式, name 字体文件名, bold 是否粗体, italic 是否斜体 +// 入参: suffix 样式后缀, bold 是否粗体, italic 是否斜体 // 返回: int 样式匹配等级 -func fontFileStyleRank(pattern, name string, bold, italic bool) int { - fileBold, fileItalic := fontFileStyle(pattern, name) +func fontFileStyleRank(suffix string, bold, italic bool) int { + fileBold, fileItalic := fontFileStyleFromSuffix(suffix) rank := 0 if fileBold != bold { rank += 2 @@ -402,7 +420,6 @@ func fontFileStyleRank(pattern, name string, bold, italic bool) int { if fileItalic != italic { rank += 2 } - suffix := fontFileStyleSuffix(pattern, name) if !bold && !italic && !fileBold && !fileItalic && suffix != "" && !fontFileRegularSuffix(suffix) { rank++ } @@ -413,7 +430,13 @@ func fontFileStyleRank(pattern, name string, bold, italic bool) int { // 入参: pattern 匹配模式, name 字体文件名 // 返回: 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" || suffix == "bd" || suffix == "bold" || diff --git a/ofdgo_font_info.go b/ofdgo_font_info.go index f20c31b..06a658f 100644 --- a/ofdgo_font_info.go +++ b/ofdgo_font_info.go @@ -225,14 +225,14 @@ func fontFSMatches(fsys fs.FS, patterns []string) []string { // 入参: fsys 字体文件系统, patterns 匹配模式列表, bold 是否粗体, italic 是否斜体 // 返回: []string 字体文件列表 func fontFSMatchesStyle(fsys fs.FS, patterns []string, bold, italic bool) []string { - var matches []fontFileMatch - seen := make(map[string]int) names, _ := fs.Glob(fsys, "*") candidates := fontFileCandidates(names, path.Base) + matches := make([]fontFileMatch, 0, len(candidates)) + seen := make(map[string]int, len(candidates)) for _, matcher := range newFontPatternMatchers(patterns) { for _, file := range candidates { - rank := matcher.rank(file.base) - appendFontFileMatch(&matches, seen, matcher.pattern, file.name, rank, bold, italic) + rank := matcher.rankCandidate(file) + appendFontFileMatch(&matches, seen, matcher, file, rank, bold, italic) } } sortFontFileMatches(matches) diff --git a/ofdgo_font_loader.go b/ofdgo_font_loader.go index 1fd06ed..a5a506c 100644 --- a/ofdgo_font_loader.go +++ b/ofdgo_font_loader.go @@ -159,14 +159,14 @@ func (r *Renderer) loadFont(fontID string) *canvas.FontFamily { // 入参: dir 目录, patterns 模式列表, bold 是否粗体, italic 是否斜体 // 返回: []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, "*")) candidates := fontFileCandidates(files, filepath.Base) + matches := make([]fontFileMatch, 0, len(candidates)) + index := make(map[string]int, len(candidates)) for _, matcher := range newFontPatternMatchers(patterns) { for _, file := range candidates { - rank := matcher.rank(file.base) - appendFontFileMatch(&matches, index, matcher.pattern, file.name, rank, bold, italic) + rank := matcher.rankCandidate(file) + appendFontFileMatch(&matches, index, matcher, file, rank, bold, italic) } } sortFontFileMatches(matches) diff --git a/ofdgo_text.go b/ofdgo_text.go index 293fea2..528a755 100644 --- a/ofdgo_text.go +++ b/ofdgo_text.go @@ -55,7 +55,7 @@ func (r *Renderer) textObjectGlyphTransforms(fontID string, text TextObject) map if fontID == "" || len(text.CGTransform) == 0 { return nil } - result := make(map[int]textGlyphTransform) + result := make(map[int]textGlyphTransform, len(text.CGTransform)) for _, transform := range text.CGTransform { ids := parseInts(transform.Glyphs) glyphCount := len(ids) @@ -69,9 +69,9 @@ func (r *Renderer) textObjectGlyphTransforms(fontID string, text TextObject) map if codeCount <= 0 { codeCount = 1 } - glyphs := make([]textGlyph, 0, glyphCount) - for i := 0; i < glyphCount; i++ { - glyphs = append(glyphs, r.textGlyphFromID(fontID, ids[i])) + glyphs := make([]textGlyph, glyphCount) + for i := range glyphs { + glyphs[i] = r.textGlyphFromID(fontID, ids[i]) } result[transform.CodePosition] = textGlyphTransform{ CodeCount: codeCount, @@ -108,9 +108,9 @@ func textCodeGlyphs(runes []rune, transforms map[int]textGlyphTransform, codeOff // 入参: runes 文本字符 // 返回: []textGlyph 绘制字形列表 func textRuneGlyphs(runes []rune) []textGlyph { - glyphs := make([]textGlyph, 0, len(runes)) - for _, r := range runes { - glyphs = append(glyphs, textGlyph{Text: string(r), GlyphID: -1}) + glyphs := make([]textGlyph, len(runes)) + for i, r := range runes { + glyphs[i] = textGlyph{Text: string(r), GlyphID: -1} } return glyphs } @@ -208,32 +208,33 @@ func (r *Renderer) fontGlyphRune(fontID string, glyphID int) (rune, bool) { // 入参: indexStr 索引字符串, fontID 字体ID // 返回: []rune 字形列表 func (r *Renderer) parseIndexRunes(indexStr string, fontID string) []rune { - var gids []int parts := strings.Fields(indexStr) + result := make([]rune, 0, len(parts)) for _, p := range parts { - if strings.Contains(p, "-") { - sub := strings.Split(p, "-") - if len(sub) == 2 { - start, _ := strconv.Atoi(sub[0]) - end, _ := strconv.Atoi(sub[1]) + if startText, endText, ok := strings.Cut(p, "-"); ok { + if !strings.Contains(endText, "-") { + start, _ := strconv.Atoi(startText) + end, _ := strconv.Atoi(endText) for k := start; k <= end; k++ { - gids = append(gids, k) + result = append(result, r.textIndexRune(fontID, k)) } } } else { val, _ := strconv.Atoi(p) - gids = append(gids, val) + result = append(result, r.textIndexRune(fontID, val)) } } - var res []rune - for _, gid := range gids { - if rVal, ok := r.fontGlyphRune(fontID, gid); ok { - res = append(res, rVal) - continue - } - res = append(res, rune(gid)) + return result +} + +// textIndexRune 获取索引字形对应的字符 +// 入参: fontID 字体ID, glyphID 字形ID或CID +// 返回: rune 字符 +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 获取显式字形推进宽度