feat(字体处理): 优化字体裁剪与依赖校验
build.yaml / build (push) Successful in 1m17s

This commit is contained in:
xiaoqidun committed 2026-10-12 16:55:10 +08:00
1 parent 7bce701907
commit 92149b220e
3 files changed
+22 -21

No files matched your search

+2 -9
View File
@@ -283,18 +283,13 @@ func subsetSourceSFNTFont(data []byte, usage *editorFontUsage) []byte {
return nil return nil
} }
} }
for id := range glyphs { dependencies, err := sfnt.glyphDependencies(slices.Collect(maps.Keys(glyphs))...)
if id >= sfnt.NumGlyphs() {
return nil
}
dependencies, err := sfnt.glyphDependencies(id)
if err != nil { if err != nil {
return nil return nil
} }
for _, dependency := range dependencies { for _, dependency := range dependencies {
glyphs[dependency] = true glyphs[dependency] = true
} }
}
var glyf, loca []byte var glyf, loca []byte
for id := 0; id <= int(sfnt.NumGlyphs()); id++ { for id := 0; id <= int(sfnt.NumGlyphs()); id++ {
if binary.BigEndian.Uint16(sfnt.Tables["head"][50:]) == 0 { if binary.BigEndian.Uint16(sfnt.Tables["head"][50:]) == 0 {
@@ -426,8 +421,7 @@ func subsetCompactSFNTFont(sfnt *sfntFont, glyphs []uint16) ([]byte, error) {
ids = append(ids, id) ids = append(ids, id)
} }
} }
for index := 0; index < len(ids); index++ { dependencies, err := sfnt.glyphDependencies(ids...)
dependencies, err := sfnt.glyphDependencies(ids[index])
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -437,7 +431,6 @@ func subsetCompactSFNTFont(sfnt *sfntFont, glyphs []uint16) ([]byte, error) {
ids = append(ids, id) ids = append(ids, id)
} }
} }
}
table := make(map[string][]byte) table := make(map[string][]byte)
for _, tag := range []string{"head", "hhea", "maxp", "OS/2", "post", "name", "cvt ", "fpgm", "prep", "gasp", "vhea"} { for _, tag := range []string{"head", "hhea", "maxp", "OS/2", "post", "name", "cvt ", "fpgm", "prep", "gasp", "vhea"} {
if data := sfnt.Tables[tag]; data != nil { if data := sfnt.Tables[tag]; data != nil {
+17 -9
View File
@@ -263,21 +263,24 @@ func (f *sfntFont) VerticalMetrics() (uint16, uint16, uint16) {
// 返回: []byte 独立字体 // 返回: []byte 独立字体
func (f *sfntFont) Write() []byte { data, _ := serializeOTF(f.Tables); return data } func (f *sfntFont) Write() []byte { data, _ := serializeOTF(f.Tables); return data }
// glyphDependencies 收集复合字形依赖,拒绝循环引用和截断记录 // glyphDependencies 批量收集复合字形依赖,校验引用、记录长度和嵌套深度
// 入参: gid 字形编号 // 入参: glyphs 字形编号
// 返回: []uint16 依赖字形, error 字形错误 // 返回: []uint16 依赖字形, error 字形错误
func (f *sfntFont) glyphDependencies(gid uint16) ([]uint16, error) { func (f *sfntFont) glyphDependencies(glyphs ...uint16) ([]uint16, error) {
seen, active := make(map[uint16]bool), make(map[uint16]bool) heights, active := make(map[uint16]int), make(map[uint16]bool)
var result []uint16 var result []uint16
var visit func(uint16) error var visit func(uint16) error
visit = func(id uint16) error { visit = func(id uint16) error {
if id >= f.count || active[id] || len(active) > 64 { if id >= f.count || active[id] || len(active) > 64 {
return fmt.Errorf("invalid composite glyph reference") return fmt.Errorf("invalid composite glyph reference")
} }
if seen[id] { if height := heights[id]; height != 0 {
if len(active)+height > 65 {
return fmt.Errorf("invalid composite glyph reference")
}
return nil return nil
} }
seen[id], active[id] = true, true heights[id], active[id] = 1, true
defer delete(active, id) defer delete(active, id)
data, err := trueTypeGlyphData(f.Tables, id) data, err := trueTypeGlyphData(f.Tables, id)
if err != nil { if err != nil {
@@ -315,18 +318,23 @@ func (f *sfntFont) glyphDependencies(gid uint16) ([]uint16, error) {
if pos > len(data) { if pos > len(data) {
return fmt.Errorf("truncated composite transform") return fmt.Errorf("truncated composite transform")
} }
if !seen[child] { if heights[child] == 0 {
result = append(result, child) result = append(result, child)
} }
if err := visit(child); err != nil { if err := visit(child); err != nil {
return err return err
} }
heights[id] = max(heights[id], heights[child]+1)
if flags&0x20 == 0 { if flags&0x20 == 0 {
break break
} }
} }
return nil return nil
} }
err := visit(gid) for _, id := range glyphs {
return result, err if err := visit(id); err != nil {
return nil, err
}
}
return result, nil
} }
+3 -3
View File
@@ -17,6 +17,8 @@ package ofdgo
import ( import (
"encoding/binary" "encoding/binary"
"fmt" "fmt"
"maps"
"slices"
) )
// variableSFNTSubsettable 核对TrueType可变轴与字形变化表的基本结构 // variableSFNTSubsettable 核对TrueType可变轴与字形变化表的基本结构
@@ -51,15 +53,13 @@ func subsetVariableSFNTFont(sfnt *sfntFont, glyphs []uint16) ([]byte, error) {
usage.chars[char] = true usage.chars[char] = true
} }
} }
for gid := range usage.glyphs { dependencies, err := sfnt.glyphDependencies(slices.Collect(maps.Keys(usage.glyphs))...)
dependencies, err := sfnt.glyphDependencies(gid)
if err != nil { if err != nil {
return nil, err return nil, err
} }
for _, dependency := range dependencies { for _, dependency := range dependencies {
usage.glyphs[dependency] = true usage.glyphs[dependency] = true
} }
}
mapping := make(map[rune]uint16, len(usage.chars)) mapping := make(map[rune]uint16, len(usage.chars))
for char := range usage.chars { for char := range usage.chars {
mapping[char] = sfnt.GlyphIndex(char) mapping[char] = sfnt.GlyphIndex(char)