Skip to content

Commit 61b5469

Browse files
committed
重构字体处理:集中字体辅助与系统字体逻辑
本次提交将字体相关逻辑集中到 LvglFontHelper 和 LinuxRuntimeFontHelper,统一了字体应用、后备字形集和系统字体解析。移除原有 LvglHostDefaults,所有平台 View 字体初始化均调用新辅助类,提升了代码复用性和健壮性。copilot-instructions.md 增补了字体处理规范说明。
1 parent 952bc24 commit 61b5469

File tree

10 files changed

+304
-135
lines changed

10 files changed

+304
-135
lines changed

.github/copilot-instructions.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
## AOT Compatibility
1111
- 在该仓库中,必须严格执行 AOT 兼容性:不要仅通过注释来抑制修剪器/AOT 警告;应替换基于反射的运行时激活路径,使用 AOT 安全的显式实现。
1212

13+
## Font Handling
14+
- 共享的后备字体处理应集中在一个核心级别的解决方案中,以便任何运行时视图都可以重用相同的策略。
15+
1316
## Recent Learnings
1417
- 排查 Linux/X11 黑屏时,先区分是“窗口已创建但未绘制”还是“控件树创建阶段卡住”。如果 `Load` 都没走到,优先检查控件树创建路径,不要先把原因归到字体解析。
1518
- 在 X11/LVGL 下做多页整屏界面时,不要在启动阶段一次性把所有隐藏整页都挂到同一个 viewport。首页先挂载,其他页按需懒加载或渐进预热,否则可能出现首屏黑屏或被隐藏页覆盖。
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
using LVGLSharp.Interop;
2+
using SixLabors.Fonts;
3+
using System.Collections.Generic;
4+
5+
namespace LVGLSharp;
6+
7+
public static unsafe class LvglFontHelper
8+
{
9+
private static readonly HashSet<uint> s_defaultFontFallbackGlyphs =
10+
[
11+
61441, 61448, 61451, 61452, 61453, 61457, 61459, 61461, 61465, 61468,
12+
61473, 61478, 61479, 61480, 61502, 61507, 61512, 61515, 61516, 61517,
13+
61521, 61522, 61523, 61524, 61543, 61544, 61550, 61552, 61553, 61556,
14+
61559, 61560, 61561, 61563, 61587, 61589, 61636, 61637, 61639, 61641,
15+
61664, 61671, 61674, 61683, 61724, 61732, 61787, 61931, 62016, 62017,
16+
62018, 62019, 62020, 62087, 62099, 62189, 62212, 62810, 63426, 63650
17+
];
18+
19+
/// <summary>
20+
/// Creates a copy of the default glyph set that should fall back to the native LVGL font.
21+
/// </summary>
22+
public static HashSet<uint> CreateDefaultFontFallbackGlyphs()
23+
{
24+
return new HashSet<uint>(s_defaultFontFallbackGlyphs);
25+
}
26+
27+
/// <summary>
28+
/// Applies the specified font to the root object and records it as the active runtime text font.
29+
/// </summary>
30+
public static lv_style_t* ApplyDefaultFontStyle(lv_obj_t* root, lv_font_t* font)
31+
{
32+
if (root == null || font == null)
33+
{
34+
return null;
35+
}
36+
37+
LvglRuntimeFontRegistry.SetActiveTextFont(font);
38+
lv_obj_set_style_text_font(root, font, 0);
39+
return null;
40+
}
41+
42+
/// <summary>
43+
/// Creates a managed font from a font file path, applies it to the root object, and records it as the active runtime font.
44+
/// </summary>
45+
public static SixLaborsFontManager ApplyManagedFont(
46+
lv_obj_t* root,
47+
string fontPath,
48+
float size,
49+
float dpi,
50+
lv_font_t* fallback,
51+
out lv_font_t* font,
52+
out lv_style_t* style)
53+
{
54+
ArgumentException.ThrowIfNullOrWhiteSpace(fontPath);
55+
56+
var manager = new SixLaborsFontManager(fontPath, size, dpi, fallback, CreateDefaultFontFallbackGlyphs());
57+
font = manager.GetLvFontPtr();
58+
style = ApplyDefaultFontStyle(root, font);
59+
return manager;
60+
}
61+
62+
/// <summary>
63+
/// Creates a managed font from a font family, applies it to the root object, and records it as the active runtime font.
64+
/// </summary>
65+
public static SixLaborsFontManager ApplyManagedFont(
66+
lv_obj_t* root,
67+
FontFamily fontFamily,
68+
float size,
69+
float dpi,
70+
lv_font_t* fallback,
71+
out lv_font_t* font,
72+
out lv_style_t* style)
73+
{
74+
ArgumentNullException.ThrowIfNull(fontFamily);
75+
76+
var manager = new SixLaborsFontManager(fontFamily, size, dpi, fallback, CreateDefaultFontFallbackGlyphs());
77+
font = manager.GetLvFontPtr();
78+
style = ApplyDefaultFontStyle(root, font);
79+
return manager;
80+
}
81+
82+
/// <summary>
83+
/// Resolves the effective text font for the object, falling back to the active runtime font and LVGL default font.
84+
/// </summary>
85+
public static lv_font_t* GetEffectiveTextFont(lv_obj_t* obj, lv_part_t part, lv_font_t* fallback = null)
86+
{
87+
if (obj != null)
88+
{
89+
try
90+
{
91+
var font = lv_obj_get_style_text_font(obj, part);
92+
if (font != null)
93+
{
94+
return font;
95+
}
96+
}
97+
catch (NullReferenceException)
98+
{
99+
// Native style resolution can surface as NullReferenceException while the
100+
// LVGL style chain is still being initialized. Fall back to the active font.
101+
}
102+
}
103+
104+
if (fallback != null)
105+
{
106+
return fallback;
107+
}
108+
109+
fallback = LvglRuntimeFontRegistry.GetActiveTextFont();
110+
if (fallback != null)
111+
{
112+
return fallback;
113+
}
114+
115+
return (lv_font_t*)lv_font_get_default();
116+
}
117+
}

src/LVGLSharp.Runtime.Linux/DrmView.cs

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -102,22 +102,12 @@ protected override void OnOpenCore()
102102

103103
_root = lv_scr_act();
104104
_keyInputGroup = lv_group_create();
105-
_fallbackFont = lv_obj_get_style_text_font(_root, lv_part_t.LV_PART_MAIN);
106-
_fontDiagnosticSummary = LinuxSystemFontResolver.GetFontPathDiagnosticSummary();
107-
_fontGlyphDiagnosticSummary = LinuxSystemFontResolver.GetGlyphDiagnosticSummary();
108-
109-
var systemFontPath = LinuxSystemFontResolver.TryResolveFontPath();
110-
if (!string.IsNullOrWhiteSpace(systemFontPath))
111-
{
112-
_fontManager = new SixLaborsFontManager(
113-
systemFontPath,
114-
12,
115-
_dpi,
116-
_fallbackFont,
117-
LvglHostDefaults.CreateDefaultFontFallbackGlyphs());
118-
119-
_defaultFontStyle = LvglHostDefaults.ApplyDefaultFontStyle(_root, _fontManager.GetLvFontPtr());
120-
}
105+
LinuxRuntimeFontHelper.InitializeRuntimeFont(_root, _dpi).ApplyDiagnosticsTo(
106+
ref _fallbackFont,
107+
ref _fontManager,
108+
ref _fontDiagnosticSummary,
109+
ref _fontGlyphDiagnosticSummary,
110+
ref _defaultFontStyle);
121111

122112
_running = true;
123113
_initialized = true;

src/LVGLSharp.Runtime.Linux/FrameBufferView.cs

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -79,20 +79,10 @@ protected override void OnOpenCore()
7979

8080
RootObject = lv_scr_act();
8181

82-
_fallbackFont = lv_obj_get_style_text_font(RootObject, lv_part_t.LV_PART_MAIN);
83-
84-
var systemFontPath = LinuxSystemFontResolver.TryResolveFontPath();
85-
if (!string.IsNullOrWhiteSpace(systemFontPath))
86-
{
87-
_fontManager = new SixLaborsFontManager(
88-
systemFontPath,
89-
12,
90-
_dpi,
91-
_fallbackFont,
92-
LvglHostDefaults.CreateDefaultFontFallbackGlyphs());
93-
94-
_defaultFontStyle = LvglHostDefaults.ApplyDefaultFontStyle(RootObject, _fontManager.GetLvFontPtr());
95-
}
82+
LinuxRuntimeFontHelper.InitializeRuntimeFont(RootObject, _dpi).ApplyTo(
83+
ref _fallbackFont,
84+
ref _fontManager,
85+
ref _defaultFontStyle);
9686
}
9787

9888
public override void RegisterTextInput(lv_obj_t* textArea)
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
using LVGLSharp.Interop;
2+
3+
namespace LVGLSharp.Runtime.Linux;
4+
5+
internal static unsafe class LinuxRuntimeFontHelper
6+
{
7+
internal readonly struct LinuxRuntimeFontInitialization
8+
{
9+
internal LinuxRuntimeFontInitialization(
10+
lv_font_t* fallbackFont,
11+
SixLaborsFontManager? fontManager,
12+
string? resolvedSystemFontPath,
13+
string fontDiagnosticSummary,
14+
string glyphDiagnosticSummary,
15+
lv_style_t* defaultFontStyle)
16+
{
17+
FallbackFont = fallbackFont;
18+
FontManager = fontManager;
19+
ResolvedSystemFontPath = resolvedSystemFontPath;
20+
FontDiagnosticSummary = fontDiagnosticSummary;
21+
GlyphDiagnosticSummary = glyphDiagnosticSummary;
22+
DefaultFontStyle = defaultFontStyle;
23+
}
24+
25+
internal lv_font_t* FallbackFont { get; }
26+
27+
internal SixLaborsFontManager? FontManager { get; }
28+
29+
internal string? ResolvedSystemFontPath { get; }
30+
31+
internal string FontDiagnosticSummary { get; }
32+
33+
internal string GlyphDiagnosticSummary { get; }
34+
35+
internal lv_style_t* DefaultFontStyle { get; }
36+
37+
internal void ApplyTo(
38+
ref lv_font_t* fallbackFont,
39+
ref SixLaborsFontManager? fontManager,
40+
ref lv_style_t* defaultFontStyle)
41+
{
42+
fallbackFont = FallbackFont;
43+
fontManager = FontManager;
44+
defaultFontStyle = DefaultFontStyle;
45+
}
46+
47+
internal void ApplyDiagnosticsTo(
48+
ref lv_font_t* fallbackFont,
49+
ref SixLaborsFontManager? fontManager,
50+
ref string? fontDiagnosticSummary,
51+
ref string? glyphDiagnosticSummary,
52+
ref lv_style_t* defaultFontStyle)
53+
{
54+
ApplyTo(ref fallbackFont, ref fontManager, ref defaultFontStyle);
55+
fontDiagnosticSummary = FontDiagnosticSummary;
56+
glyphDiagnosticSummary = GlyphDiagnosticSummary;
57+
}
58+
59+
internal void ApplyPathAndDiagnosticTo(
60+
ref lv_font_t* fallbackFont,
61+
ref SixLaborsFontManager? fontManager,
62+
ref string? resolvedSystemFontPath,
63+
ref string? fontDiagnosticSummary,
64+
ref lv_style_t* defaultFontStyle)
65+
{
66+
ApplyTo(ref fallbackFont, ref fontManager, ref defaultFontStyle);
67+
resolvedSystemFontPath = ResolvedSystemFontPath;
68+
fontDiagnosticSummary = FontDiagnosticSummary;
69+
}
70+
71+
internal void ApplyFullTo(
72+
ref lv_font_t* fallbackFont,
73+
ref SixLaborsFontManager? fontManager,
74+
ref string? resolvedSystemFontPath,
75+
ref string? fontDiagnosticSummary,
76+
ref string? glyphDiagnosticSummary,
77+
ref lv_style_t* defaultFontStyle)
78+
{
79+
ApplyTo(ref fallbackFont, ref fontManager, ref defaultFontStyle);
80+
resolvedSystemFontPath = ResolvedSystemFontPath;
81+
fontDiagnosticSummary = FontDiagnosticSummary;
82+
glyphDiagnosticSummary = GlyphDiagnosticSummary;
83+
}
84+
}
85+
86+
internal static LinuxRuntimeFontInitialization InitializeRuntimeFont(
87+
lv_obj_t* root,
88+
float dpi,
89+
bool disableManagedFont = false,
90+
float size = 12)
91+
{
92+
var fallbackFont = LvglFontHelper.GetEffectiveTextFont(root, lv_part_t.LV_PART_MAIN);
93+
var fontManager = TryApplySystemFont(
94+
root,
95+
dpi,
96+
fallbackFont,
97+
out var resolvedSystemFontPath,
98+
out var fontDiagnosticSummary,
99+
out var glyphDiagnosticSummary,
100+
out var defaultFontStyle,
101+
disableManagedFont,
102+
size);
103+
104+
return new LinuxRuntimeFontInitialization(
105+
fallbackFont,
106+
fontManager,
107+
resolvedSystemFontPath,
108+
fontDiagnosticSummary,
109+
glyphDiagnosticSummary,
110+
defaultFontStyle);
111+
}
112+
113+
internal static SixLaborsFontManager? TryApplySystemFont(
114+
lv_obj_t* root,
115+
float dpi,
116+
lv_font_t* fallback,
117+
out string? resolvedSystemFontPath,
118+
out string fontDiagnosticSummary,
119+
out string glyphDiagnosticSummary,
120+
out lv_style_t* defaultFontStyle,
121+
bool disableManagedFont = false,
122+
float size = 12)
123+
{
124+
fontDiagnosticSummary = LinuxSystemFontResolver.GetFontPathDiagnosticSummary();
125+
glyphDiagnosticSummary = LinuxSystemFontResolver.GetGlyphDiagnosticSummary();
126+
resolvedSystemFontPath = disableManagedFont ? null : LinuxSystemFontResolver.TryResolveFontPath();
127+
defaultFontStyle = null;
128+
129+
if (string.IsNullOrWhiteSpace(resolvedSystemFontPath))
130+
{
131+
return null;
132+
}
133+
134+
return LvglFontHelper.ApplyManagedFont(
135+
root,
136+
resolvedSystemFontPath,
137+
size,
138+
dpi,
139+
fallback,
140+
out _,
141+
out defaultFontStyle);
142+
}
143+
}

src/LVGLSharp.Runtime.Linux/LvglHostDefaults.cs

Lines changed: 0 additions & 38 deletions
This file was deleted.

src/LVGLSharp.Runtime.Linux/SdlView.cs

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -78,22 +78,13 @@ protected override void OnOpenCore()
7878
_root = lv_scr_act();
7979
_keyInputGroup = lv_group_create();
8080
lv_indev_set_group(_keyboardIndev, _keyInputGroup);
81-
_fallbackFont = lv_obj_get_style_text_font(_root, lv_part_t.LV_PART_MAIN);
82-
_fontDiagnosticSummary = LinuxSystemFontResolver.GetFontPathDiagnosticSummary();
83-
_fontGlyphDiagnosticSummary = LinuxSystemFontResolver.GetGlyphDiagnosticSummary();
84-
85-
_resolvedSystemFontPath = LinuxSystemFontResolver.TryResolveFontPath();
86-
if (!string.IsNullOrWhiteSpace(_resolvedSystemFontPath))
87-
{
88-
_fontManager = new SixLaborsFontManager(
89-
_resolvedSystemFontPath,
90-
12,
91-
_dpi,
92-
_fallbackFont,
93-
LvglHostDefaults.CreateDefaultFontFallbackGlyphs());
94-
95-
_defaultFontStyle = LvglHostDefaults.ApplyDefaultFontStyle(_root, _fontManager.GetLvFontPtr());
96-
}
81+
LinuxRuntimeFontHelper.InitializeRuntimeFont(_root, _dpi).ApplyFullTo(
82+
ref _fallbackFont,
83+
ref _fontManager,
84+
ref _resolvedSystemFontPath,
85+
ref _fontDiagnosticSummary,
86+
ref _fontGlyphDiagnosticSummary,
87+
ref _defaultFontStyle);
9788

9889
s_activeView = this;
9990
_running = true;

0 commit comments

Comments
 (0)