Skip to content

Commit 5c52c20

Browse files
da-liiiclaude
andcommitted
[0126] 优化 smart_font 字体加载性能
通过缓存避免字体加载过程中的重复调用: 1. 添加 maybe_initialize_font,避免对已初始化子字体重复调用 initialize_font 2. 缓存 family tokenize 结果,避免 resolve 和 is_italic_prime 中重复分割字符串 3. 缓存 logical_font 结果,避免 resolve(c, fam, attempt) 中重复计算 4. 缓存 is_italic_prime 的结果 同时添加 test_performance 和 test_math_performance 回归测试。 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent b64c6f9 commit 5c52c20

3 files changed

Lines changed: 76 additions & 31 deletions

File tree

src/Graphics/Fonts/smart_font.cpp

Lines changed: 43 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ bool virtually_defined (string c, string name);
3434
font smart_font_bis (string f, string v, string s, string sh, double sz,
3535
int hdpi, int vdpi);
3636

37+
3738
smart_map
3839
get_smart_map (tree fn) {
3940
string name= recompose (tuple_as_array (fn), "-");
@@ -625,14 +626,17 @@ smart_font_rep::smart_font_rep (string name, font base_fn, font err_fn,
625626
fn[SUBFONT_MAIN] = adjust_subfont (base_fn);
626627
fn[SUBFONT_ERROR]= adjust_subfont (err_fn);
627628
this->copy_math_pars (base_fn);
629+
family_tokens = trimmed_tokenize (family, ",");
630+
given_font = logical_font (family, variant, series, rshape);
631+
italic_prime_cached = false;
628632
if (shape == "mathitalic" || shape == "mathupright" || shape == "mathshape") {
629633
if (is_math_family (mfam)) {
630634
rshape= "right";
631635
if (shape == "mathupright") this->copy_math_pars (base_fn);
632636
else {
633637
tree key= tuple ("math", mfam, variant, series, rshape);
634638
int nr = sm->add_font (key, REWRITE_MATH);
635-
initialize_font (nr);
639+
maybe_initialize_font (nr);
636640
this->copy_math_pars (fn[nr]);
637641
fn[SUBFONT_MAIN]= fn[nr];
638642
}
@@ -645,7 +649,7 @@ smart_font_rep::smart_font_rep (string name, font base_fn, font err_fn,
645649
if (math_kind == 2) this->copy_math_pars (base_fn);
646650
else {
647651
italic_nr= sm->add_font (tuple ("fast-italic"), REWRITE_NONE);
648-
initialize_font (italic_nr);
652+
maybe_initialize_font (italic_nr);
649653
this->copy_math_pars (fn[italic_nr]);
650654
}
651655
(void) sm->add_font (tuple ("special"), REWRITE_SPECIAL);
@@ -836,7 +840,7 @@ smart_font_rep::advance (string s, int& pos, string& r, int& nr) {
836840
}
837841

838842
if (count == 1 && nr != -1 && fn_index == nr) {
839-
if (N (fn) <= nr || is_nil (fn[nr])) initialize_font (nr);
843+
maybe_initialize_font (nr);
840844
if (!fn[nr]->supports (s (start, end))) break;
841845
pos= end;
842846
}
@@ -851,7 +855,7 @@ smart_font_rep::advance (string s, int& pos, string& r, int& nr) {
851855
}
852856
r= s (start, pos);
853857
if (nr < 0) return;
854-
if (N (fn) <= nr || is_nil (fn[nr])) initialize_font (nr);
858+
maybe_initialize_font (nr);
855859
if (sm->fn_rewr[nr] != REWRITE_NONE) r= rewrite (r, sm->fn_rewr[nr]);
856860
}
857861
if (DEBUG_VERBOSE) {
@@ -911,10 +915,9 @@ smart_font_rep::resolve (string c, string fam, int attempt) {
911915
}
912916
array<string> a= trimmed_tokenize (fam, "=");
913917
if (N (a) >= 2) {
914-
array<string> given= logical_font (family, variant, series, rshape);
915918
fam = a[1];
916919
array<string> b = tokenize (a[0], " ");
917-
bool ok = is_wanted (c, fam, b, given);
920+
bool ok = is_wanted (c, fam, b, given_font);
918921
if (!ok) {
919922
return -1;
920923
}
@@ -930,7 +933,7 @@ smart_font_rep::resolve (string c, string fam, int attempt) {
930933
if (cfn->supports (c)) {
931934
tree key= tuple ("subfont", fam);
932935
int nr = sm->add_font (key, REWRITE_NONE);
933-
initialize_font (nr);
936+
maybe_initialize_font (nr);
934937
return sm->add_char (key, c);
935938
}
936939
}
@@ -957,41 +960,41 @@ smart_font_rep::resolve (string c, string fam, int attempt) {
957960
if (cfn->supports (c) || c == "<#200B>") {
958961
tree key= tuple (fam, variant, series, rshape, "1");
959962
int nr = sm->add_font (key, REWRITE_NONE);
960-
initialize_font (nr);
963+
maybe_initialize_font (nr);
961964
return sm->add_char (key, c);
962965
}
963966
}
964967

965968
if (fam == "roman" && range == "greek") {
966969
tree key= tuple ("greek", fam, variant, series, rshape);
967970
int nr = sm->add_font (key, REWRITE_NONE);
968-
initialize_font (nr);
971+
maybe_initialize_font (nr);
969972
return sm->add_char (key, c);
970973
}
971974
if (fam == "roman" && range == "latin") {
972975
tree key= tuple ("latin", fam, variant, series, rshape);
973976
int nr = sm->add_font (key, REWRITE_NONE);
974-
initialize_font (nr);
977+
maybe_initialize_font (nr);
975978
return sm->add_char (key, c);
976979
}
977980
if (is_math_family (fam)) {
978981
tree key= tuple ("math", fam, variant, series, rshape);
979982
int nr = sm->add_font (key, REWRITE_MATH);
980-
initialize_font (nr);
983+
maybe_initialize_font (nr);
981984
if (fn[nr]->supports (rewrite (c, REWRITE_MATH)))
982985
return sm->add_char (key, c);
983986
}
984987
if ((fam == "roman" || fam == "cyrillic") && N (c) > 1) {
985988
tree key= tuple ("cyrillic", fam, variant, series, rshape);
986989
int nr = sm->add_font (key, REWRITE_CYRILLIC);
987-
initialize_font (nr);
990+
maybe_initialize_font (nr);
988991
if (fn[nr]->supports (rewrite (c, REWRITE_CYRILLIC)))
989992
return sm->add_char (key, c);
990993
}
991994
if (c == "<#3000>") {
992995
tree key= tuple ("ignore");
993996
int nr = sm->add_font (key, REWRITE_IGNORE);
994-
initialize_font (nr);
997+
maybe_initialize_font (nr);
995998
return sm->add_char (key, c);
996999
}
9971000
if (N (c) == 7 && starts (c, "<bbb-") && !occurs ("TeX Gyre", mfam)) {
@@ -1009,14 +1012,14 @@ smart_font_rep::resolve (string c, string fam, int attempt) {
10091012
vw = max (vw, 0.25 * lw);
10101013
tree key = tuple ("poor-bbb", as_string (hw), as_string (vw));
10111014
int nr = sm->add_font (key, REWRITE_POOR_BBB);
1012-
initialize_font (nr);
1015+
maybe_initialize_font (nr);
10131016
return sm->add_char (key, c);
10141017
}
10151018
}
10161019
if (starts (c, "<it-") && ends (c, ">")) {
10171020
tree key= tuple ("it");
10181021
int nr = sm->add_font (key, REWRITE_ITALIC);
1019-
initialize_font (nr);
1022+
maybe_initialize_font (nr);
10201023
return sm->add_char (key, c);
10211024
}
10221025
if (fam == mfam && !is_italic_font (mfam)) {
@@ -1025,7 +1028,7 @@ smart_font_rep::resolve (string c, string fam, int attempt) {
10251028
if (virtually_defined (c, emu_names[i])) {
10261029
tree key= tuple ("emulate", emu_names[i]);
10271030
int nr = sm->add_font (key, REWRITE_NONE);
1028-
initialize_font (nr);
1031+
maybe_initialize_font (nr);
10291032
if (fn[nr]->supports (c)) return sm->add_char (key, c);
10301033
}
10311034
}
@@ -1045,7 +1048,7 @@ smart_font_rep::resolve (string c, string fam, int attempt) {
10451048
if (cfn->supports (c) || c == "<#200B>") {
10461049
tree key= tuple (fam, v, series, rshape, as_string (a));
10471050
int nr = sm->add_font (key, REWRITE_NONE);
1048-
initialize_font (nr);
1051+
maybe_initialize_font (nr);
10491052
return sm->add_char (key, c);
10501053
}
10511054
}
@@ -1056,12 +1059,18 @@ smart_font_rep::resolve (string c, string fam, int attempt) {
10561059
bool
10571060
smart_font_rep::is_italic_prime (string c) {
10581061
if (c != "'" && c != "`") return false;
1059-
array<string> a= trimmed_tokenize (family, ",");
1062+
if (italic_prime_cached) return italic_prime_result;
10601063
string s= "<#2B9>";
10611064
if (c == "`") s= "<backprime>";
1062-
for (int i= 0; i < N (a); i++)
1063-
if (resolve (s, a[i], 1) >= 0) return false;
1064-
return true;
1065+
bool result= true;
1066+
for (int i= 0; i < N (family_tokens); i++)
1067+
if (resolve (s, family_tokens[i], 1) >= 0) {
1068+
result= false;
1069+
break;
1070+
}
1071+
italic_prime_cached = true;
1072+
italic_prime_result = result;
1073+
return result;
10651074
}
10661075

10671076
extern bool has_poor_rubber;
@@ -1079,7 +1088,7 @@ smart_font_rep::resolve_rubber (string c, string fam, int attempt) {
10791088
if (goal == "." || goal == "<nobracket>") {
10801089
tree key= tuple ("ignore");
10811090
int nr = sm->add_font (key, REWRITE_IGNORE);
1082-
initialize_font (nr);
1091+
maybe_initialize_font (nr);
10831092
return sm->add_char (key, c);
10841093
}
10851094
if (has_poor_rubber) {
@@ -1101,7 +1110,7 @@ smart_font_rep::resolve_rubber (string c, string fam, int attempt) {
11011110
if (bnr >= 0 && bnr < N (fn) && !is_nil (fn[bnr])) {
11021111
tree key= tuple ("rubber", as_string (bnr));
11031112
int nr = sm->add_font (key, REWRITE_NONE);
1104-
initialize_font (nr);
1113+
maybe_initialize_font (nr);
11051114
// cout << fn[nr]->res_name << " supports " << c << "? "
11061115
// << fn[nr]->supports (c) << LF;
11071116
if (fn[nr]->supports (c)) return sm->add_char (key, c);
@@ -1138,7 +1147,7 @@ smart_font_rep::resolve (string c) {
11381147
debug_fonts << "Main subfont of " << cork_to_utf8 (c) << " is "
11391148
<< fn[SUBFONT_MAIN]->res_name << LF;
11401149
}
1141-
array<string> a= trimmed_tokenize (family, ",");
1150+
array<string> a= family_tokens;
11421151

11431152
// Special handling for emoji characters - bypass font-family restrictions
11441153
string range= get_unicode_range (c);
@@ -1167,7 +1176,7 @@ smart_font_rep::resolve (string c) {
11671176
if (!is_nil (cfn) && cfn->supports (c)) {
11681177
tree key= tuple ("emoji-font", parts[1]);
11691178
int nr = sm->add_font (key, REWRITE_NONE);
1170-
initialize_font (nr);
1179+
maybe_initialize_font (nr);
11711180
return sm->add_char (key, c);
11721181
}
11731182
}
@@ -1179,22 +1188,22 @@ smart_font_rep::resolve (string c) {
11791188
if (upc != "" && fn[SUBFONT_MAIN]->supports (upc)) {
11801189
tree key= tuple ("up");
11811190
int nr = sm->add_font (key, REWRITE_UPRIGHT);
1182-
initialize_font (nr);
1191+
maybe_initialize_font (nr);
11831192
return sm->add_char (key, c);
11841193
}
11851194
string ugc= substitute_upright_greek (c);
11861195
if (ugc != "" && fn[SUBFONT_MAIN]->supports (ugc)) {
11871196
tree key= tuple ("upright-greek");
11881197
int nr = sm->add_font (key, REWRITE_UPRIGHT_GREEK);
1189-
initialize_font (nr);
1198+
maybe_initialize_font (nr);
11901199
return sm->add_char (key, c);
11911200
}
11921201
if (is_greek (c) && use_italic_greek (a) && shape != "mathupright") {
11931202
string gc= substitute_italic_greek (c);
11941203
if (gc != "" && fn[SUBFONT_MAIN]->supports (gc)) {
11951204
tree key= tuple ("italic-greek");
11961205
int nr = sm->add_font (key, REWRITE_ITALIC_GREEK);
1197-
initialize_font (nr);
1206+
maybe_initialize_font (nr);
11981207
return sm->add_char (key, c);
11991208
}
12001209
// cout << "Found " << c << " in greek\n";
@@ -1371,7 +1380,7 @@ smart_font_rep::initialize_font (int nr) {
13711380
fn[nr] = poor_bbb_font (sfn, pw, ph, 1.5 * pw);
13721381
}
13731382
else if (a[0] == "rubber" && N (a) == 2 && is_int (a[1])) {
1374-
initialize_font (as_int (a[1]));
1383+
maybe_initialize_font (as_int (a[1]));
13751384
fn[nr]= adjust_subfont (rubber_font (fn[as_int (a[1])]));
13761385
// fn[nr]= adjust_subfont (rubber_unicode_font (fn[as_int (a[1])]));
13771386
}
@@ -1388,6 +1397,11 @@ smart_font_rep::initialize_font (int nr) {
13881397
}
13891398
}
13901399

1400+
void
1401+
smart_font_rep::maybe_initialize_font (int nr) {
1402+
if (N (fn) <= nr || is_nil (fn[nr])) initialize_font (nr);
1403+
}
1404+
13911405
static int
13921406
get_ex (string family, string variant, string series, string shape,
13931407
int attempt) {

src/Graphics/Fonts/smart_font.hpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,12 @@ struct smart_font_rep : font_rep {
9999
int math_kind;
100100
int italic_nr;
101101

102-
array<font> fn;
103-
smart_map sm;
102+
array<font> fn;
103+
smart_map sm;
104+
array<string> family_tokens;
105+
array<string> given_font;
106+
bool italic_prime_cached;
107+
bool italic_prime_result;
104108

105109
smart_font_rep (string name, font base_fn, font err_fn, string family,
106110
string variant, string series, string shape, double sz,
@@ -117,6 +121,7 @@ struct smart_font_rep : font_rep {
117121
int resolve_rubber (string c, string fam, int attempt);
118122
int resolve (string c);
119123
void initialize_font (int nr);
124+
void maybe_initialize_font (int nr);
120125
int adjusted_dpi (string fam, string var, string ser, string sh, int att);
121126

122127
font make_rubber_font (font base) override;

tests/Graphics/Fonts/smart_font_test.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ private slots:
3838
void test_get_right_slope ();
3939
void test_latin_modern_math_italic_greek ();
4040
void test_cursor_position_iii ();
41+
void test_performance ();
42+
void test_math_performance ();
4143
};
4244

4345
void
@@ -161,5 +163,29 @@ TestSmartFont::test_cursor_position_iii () {
161163
STACK_DELETE_ARRAY (xpos);
162164
}
163165

166+
void
167+
TestSmartFont::test_performance () {
168+
font fn= smart_font ("sys-chinese", "rm", "medium", "right", 10, 600);
169+
170+
// Trigger a lot of character resolutions with repeated characters
171+
string long_text= "The quick brown fox jumps over the lazy dog. "
172+
"The quick brown fox jumps over the lazy dog. "
173+
"The quick brown fox jumps over the lazy dog.";
174+
metric ex;
175+
fn->get_extents (long_text, ex);
176+
}
177+
178+
void
179+
TestSmartFont::test_math_performance () {
180+
font fn= smart_font ("Latin Modern Math", "rm", "medium", "mathitalic", 10, 600);
181+
182+
// Trigger math character resolutions
183+
string math_text= "<alpha><beta><gamma><delta><epsilon><zeta><eta><theta>"
184+
"<iota><kappa><lambda><mu><nu><xi><omicron><pi><rho><sigma>"
185+
"<tau><upsilon><phi><chi><psi><omega>";
186+
metric ex;
187+
fn->get_extents (math_text, ex);
188+
}
189+
164190
QTEST_MAIN (TestSmartFont)
165191
#include "smart_font_test.moc"

0 commit comments

Comments
 (0)