Skip to content

Commit faf3c6a

Browse files
committed
refactor(cn-font-split): AI 重构代码以提高可维护性和性能
1 parent cbf1183 commit faf3c6a

File tree

7 files changed

+109
-121
lines changed

7 files changed

+109
-121
lines changed

src/link_subset/mod.rs

+14-13
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,25 @@ use crate::{message::EventFactory, runner::Context};
44
use cn_font_proto::{api_interface::EventMessage, INDEX_PROTO};
55

66
const HTML_TEMPLATE: &[u8] = include_bytes!("./index.html");
7+
8+
// 公共的文件输出逻辑
9+
fn output_file(ctx: &mut Context, file_name: &str, content: Vec<u8>) {
10+
(ctx.callback)(EventMessage::output_data(file_name, content));
11+
}
12+
713
pub fn link_subset(ctx: &mut Context) {
814
let css = ctx.input.css.clone().unwrap_or_default();
915

1016
let css_code = output_css::output_css(ctx, &css);
1117
// 输出 CSS 文件
12-
let file_name = css.file_name.unwrap_or("result.css".to_string());
13-
(ctx.callback)(EventMessage::output_data(
14-
&file_name,
15-
css_code.as_bytes().to_vec(),
16-
));
18+
let css_file_name = css.file_name.unwrap_or("result.css".to_string());
19+
output_file(ctx, &css_file_name, css_code.as_bytes().to_vec());
20+
21+
// 输出 HTML 文件(如果需要)
1722
if ctx.input.test_html.unwrap_or(true) {
18-
(ctx.callback)(EventMessage::output_data(
19-
"index.html",
20-
HTML_TEMPLATE.to_vec(),
21-
));
23+
output_file(ctx, "index.html", HTML_TEMPLATE.to_vec());
2224
}
23-
(ctx.callback)(EventMessage::output_data(
24-
"index.proto",
25-
INDEX_PROTO.to_vec(),
26-
));
25+
26+
// 输出 PROTO 文件
27+
output_file(ctx, "index.proto", INDEX_PROTO.to_vec());
2728
}

src/link_subset/output_css.rs

+46-59
Original file line numberDiff line numberDiff line change
@@ -9,70 +9,68 @@ pub fn output_css(ctx: &mut Context, css: &CssProperties) -> String {
99
let name_table = &ctx.name_table;
1010

1111
// fontData.preferredFamily 不使用这个,因为这个容易引起歧义
12-
let font_family: String = css.font_family.clone().unwrap_or(
12+
let font_family = css.font_family.clone().unwrap_or_else(|| {
1313
name_table
1414
.get_name_first("FontFamilyName")
15-
.unwrap_or("default_font_family".to_string()),
16-
);
15+
.unwrap_or("default_font_family".to_string())
16+
});
1717

1818
// 优先使用preferredSubFamily,如果没有,则使用fontSubFamily或fontSubfamily。
19+
// 提取字体样式
1920
let preferred_sub_family =
20-
name_table.get_name_first("FontSubfamilyName").unwrap_or(
21-
name_table.get_name_first("FullFontName").unwrap_or("".to_string()),
22-
);
23-
let font_style =
24-
css.font_style.clone().unwrap_or(if is_italic(&preferred_sub_family) {
21+
name_table.get_name_first("FontSubfamilyName").unwrap_or_else(|| {
22+
name_table.get_name_first("FullFontName").unwrap_or("".to_string())
23+
});
24+
let font_style = css.font_style.clone().unwrap_or_else(|| {
25+
if is_italic(&preferred_sub_family) {
2526
"italic".to_string()
2627
} else {
2728
"normal".to_string()
28-
});
29+
}
30+
});
2931

30-
let font_weight = css.font_weight.clone().unwrap_or(
32+
// 提取字体权重
33+
let font_weight = css.font_weight.clone().unwrap_or_else(|| {
3134
ctx.fvar_table
3235
.clone()
3336
.map(|x| x.vf_weight)
34-
.unwrap_or(get_weight(&preferred_sub_family).to_string()),
35-
);
37+
.unwrap_or(get_weight(&preferred_sub_family).to_string())
38+
});
3639

37-
// 创建本地字体声明字符串。
40+
// 生成本地字体声明
3841
let locals = if css.local_family.len() == 0 {
3942
vec![font_family.clone()]
4043
} else {
4144
css.local_family.clone()
4245
};
4346
let locals = locals
4447
.iter()
45-
.map(|x| format!("local(\"{x}\")").clone())
48+
.map(|x| format!("local(\"{x}\")"))
4649
.collect::<Vec<String>>();
4750

51+
// 生成 polyfill 字符串
4852
let polyfill_str = css
4953
.polyfill
5054
.iter()
51-
.map(|p| {
52-
format!(
53-
"url(\"{}\") {}",
54-
p.name,
55-
format!("format(\"{}\")", p.format)
56-
)
57-
})
55+
.map(|p| format!(r#"url("{}") format("{}")"#, p.name, p.format))
5856
.collect::<Vec<String>>()
5957
.join(",");
6058

6159
let display = css.font_display.clone().unwrap_or("swap".to_string());
62-
let codes: Vec<String> = ctx
60+
// 生成 @font-face 规则
61+
let codes = ctx
6362
.run_subset_result
6463
.iter()
6564
.rev()
6665
.map(|res| {
67-
let src_str: String = [
66+
let src_str = [
6867
locals.join(","),
69-
format!(r#"url("./{}")format("woff2")"#, res.file_name.clone()),
68+
format!(r#"url("./{}")format("woff2")"#, res.file_name),
7069
]
7170
.join(",")
72-
+ polyfill_str.as_str();
73-
let unicode_range = &UnicodeRange::stringify(&res.unicodes);
74-
let space =
75-
if css.compress.unwrap_or(true) == true { "" } else { " " };
71+
+ &polyfill_str;
72+
let unicode_range = UnicodeRange::stringify(&res.unicodes);
73+
let space = if css.compress.unwrap_or(true) { "" } else { " " };
7674
let face_code = format!(
7775
r#"@font-face{{
7876
{space}font-family:"{font_family}";
@@ -83,24 +81,20 @@ pub fn output_css(ctx: &mut Context, css: &CssProperties) -> String {
8381
{space}unicode-range:{unicode_range};
8482
}}"#
8583
);
86-
// css 这个句尾不需要分号😭
87-
// 根据注释设置生成Unicode范围的注释。
8884
let comment = if css.comment_unicodes.unwrap_or(false) {
89-
let code_string = vec_u32_to_string(&res.unicodes);
90-
format!("/* {} */\n", code_string)
85+
format!("/* {} */\n", vec_u32_to_string(&res.unicodes))
9186
} else {
9287
"".to_string()
9388
};
94-
// 根据压缩选项返回压缩或未压缩的样式字符串。
95-
9689
let compressed = if css.compress.unwrap_or(true) {
9790
face_code.replace("\n", "")
9891
} else {
9992
face_code
10093
};
10194
comment + &compressed
10295
})
103-
.collect();
96+
.collect::<Vec<String>>();
97+
10498
ctx.reporter.css = Some(output_report::Css {
10599
family: font_family.clone(),
106100
style: font_style.clone(),
@@ -110,26 +104,24 @@ pub fn output_css(ctx: &mut Context, css: &CssProperties) -> String {
110104

111105
let header_comment = create_header_comment(ctx, css);
112106

113-
header_comment + &codes.join("\n")
107+
header_comment + &codes.join("")
114108
}
115109

116110
fn create_header_comment(
117111
ctx: &mut Context<'_, '_, '_>,
118112
css: &CssProperties,
119113
) -> String {
120-
// ctx.input.css.and_then(|x|x.comment_base)
121-
let mut comment = String::from("");
114+
let mut comment = String::new();
122115

123116
if css.comment_base.unwrap_or(true) {
124-
let utc: DateTime<Utc> = Utc::now();
125-
let base_comment = format!("Generated By cn-font-split@{} https://www.npmjs.com/package/cn-font-split\nCreateTime: {};",
117+
let utc = Utc::now();
118+
comment.push_str(&format!(
119+
"Generated By cn-font-split@{} https://www.npmjs.com/package/cn-font-split\nCreateTime: {};\n",
126120
ctx.reporter.version,
127-
utc.to_string()
128-
);
129-
comment.push_str(&base_comment);
121+
utc.to_rfc3339()
122+
));
130123
}
131124

132-
// name table 的转换
133125
if css.comment_name_table.unwrap_or(true) {
134126
let name_table_comment = ctx
135127
.name_table
@@ -140,15 +132,20 @@ fn create_header_comment(
140132
})
141133
.collect::<Vec<String>>()
142134
.join("\n");
143-
144-
comment.push_str("\n");
145135
comment.push_str(&name_table_comment);
146136
}
147137

148-
if comment.len() == 0 {
149-
return String::from("");
138+
if comment.is_empty() {
139+
return String::new();
150140
}
151-
"/* ".to_owned() + &comment + "\n */\n\n"
141+
format!("/* {}\n */\n\n", comment.trim())
142+
}
143+
144+
pub fn get_weight(sub_family: &str) -> u32 {
145+
let sub_family = sub_family.to_ascii_lowercase();
146+
FONT_WEIGHT_NAME
147+
.binary_search_by_key(&sub_family.as_str(), |&(name, _)| name)
148+
.map_or(600, |idx| FONT_WEIGHT_NAME[idx].1)
152149
}
153150

154151
/** 判断是否为斜体 */
@@ -173,13 +170,3 @@ const FONT_WEIGHT_NAME: [(&str, u32); 15] = [
173170
("heavy", 900),
174171
("black", 900),
175172
];
176-
177-
pub fn get_weight(sub_family: &str) -> u32 {
178-
let sub_family = sub_family.to_ascii_lowercase();
179-
for (name, weight) in FONT_WEIGHT_NAME {
180-
if sub_family.contains(name) {
181-
return weight;
182-
}
183-
}
184-
600
185-
}

src/pre_subset/features.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use cmap::analyze_cmap;
22
use gpos::analyze_gpos;
33
use gsub::analyze_gsub;
44
use indexmap::IndexSet;
5-
use std::collections::{HashMap, BTreeSet};
5+
use std::collections::{BTreeSet, HashMap};
66

77
use super::PreSubsetContext;
88
pub mod cmap;

src/pre_subset/features/gsub.rs

+4-7
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,19 @@ pub fn analyze_gsub(
88
font: &Font,
99
font_file: &mut Cursor<&[u8]>,
1010
) -> Vec<Vec<u16>> {
11-
// 丑陋的多层 unwrap 处理
1211
let temp: Result<Option<GlyphSubstitution>, std::io::Error> =
1312
font.take(font_file);
1413
// 国标宋体,解析就报错,所以干脆先不解析
15-
if temp.is_err() {
16-
error!("{}", temp.unwrap_err());
14+
if let Err(e) = temp {
15+
error!("{}", e);
1716
return vec![vec![]];
1817
}
1918

2019
// GSUB
21-
let temp1 = temp.unwrap();
22-
if temp1.is_none() {
20+
let Some(data) = temp.unwrap() else {
2321
error!("Font without GSUB table");
2422
return vec![vec![]];
25-
}
26-
let data: GlyphSubstitution = temp1.unwrap();
23+
};
2724

2825
// let mut feature_tags: Vec<&str> = data
2926
// .features

src/pre_subset/mod.rs

+16-4
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,11 @@ use plugin::{
1717
};
1818
use plugin_auto_subset::plugin_auto_subset;
1919
use std::{
20-
collections::{HashMap, BTreeSet},
20+
collections::{BTreeSet, HashMap},
2121
io::Cursor,
2222
};
2323

24+
// 定义预处理上下文结构体,用于存储预处理阶段的各种状态和数据
2425
pub struct PreSubsetContext<'a, 'b, 'c>
2526
where
2627
'b: 'a,
@@ -35,20 +36,26 @@ where
3536
used_languages: HashMap<usize, String>,
3637
}
3738

39+
// 主要的预处理函数,用于执行字体的预处理和子集化操作
3840
pub fn pre_subset(ctx: &mut Context) {
41+
// 初始化二进制文件数据和所有Unicode字符的集合
3942
let file_binary = &*ctx.binary;
4043
let mut all_unicodes: BTreeSet<u32> =
4144
BTreeSet::from_iter(ctx.face.collect_unicodes());
4245

46+
// 创建字体文件游标并读取字体数据
4347
let mut font_file = Cursor::new(file_binary);
4448
let font = opentype::Font::read(&mut font_file)
4549
.expect("cn-font-split | pre_subset | read font file error");
4650

51+
// 生成SVG图像
4752
gen_svg_from_ctx(ctx);
4853

49-
let mut subsets: Vec<IndexSet<u32>> = vec![];
5054
let user_subsets: Vec<Vec<u32>> =
5155
ctx.input.subsets.iter().map(|x| u8_array_to_u32_array(x)).collect();
56+
57+
// 初始化预处理上下文
58+
let mut subsets: Vec<IndexSet<u32>> = vec![];
5259
let mut context = PreSubsetContext {
5360
all_unicodes: all_unicodes.clone(),
5461
face: &mut ctx.face,
@@ -61,6 +68,7 @@ pub fn pre_subset(ctx: &mut Context) {
6168
used_languages: HashMap::new(),
6269
};
6370

71+
// 初始化处理流程,根据输入配置决定是否启用各个插件功能
6472
let mut process: Vec<
6573
fn(
6674
&mut Vec<IndexSet<u32>>,
@@ -85,13 +93,17 @@ pub fn pre_subset(ctx: &mut Context) {
8593
if ctx.input.reduce_mins.unwrap_or(false) {
8694
process.push(reduce_min_plugin);
8795
}
96+
// 执行所有启用的插件处理流程
8897
for p in process {
8998
p(&mut subsets, &mut all_unicodes, &mut context);
9099
}
100+
// 根据处理结果更新上下文的预处理子集结果
91101
ctx.pre_subset_result = subsets
92102
.iter()
93-
.filter(|v| v.len() > 0)
94-
.map(|v| v.iter().map(|i| i.clone()).collect::<Vec<u32>>())
103+
.filter(|v| !v.is_empty())
104+
.map(|v| v.iter().copied().collect::<Vec<u32>>())
95105
.collect();
106+
107+
// 分析并更新名称表
96108
ctx.name_table = name_table::analyze_name_table(&font, &mut font_file);
97109
}

0 commit comments

Comments
 (0)