尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

读 WPF 源代码 了解获取 GlyphTypeface 的 CharacterToGlyphMap 的数量耗时原因

读 WPF 源代码 了解获取 GlyphTypeface 的 CharacterToGlyphMap 的数量耗时原因
📅 发布时间:2026/6/20 11:49:42
在我的一次应用性能分析中,我发现了尝试获取 GlyphTypeface 的 CharacterToGlyphMap 属性的数量时,存在很大的耗时。经过阅读 WPF 源代码,我了解到了其中的原因,本文将和大家从底层源代码分析原因和给出解决方法

在 WPF 里面的 GlyphTypeface 表示字体的字形信息,通过 GlyphTypeface.CharacterToGlyphMap 属性可以将给定的字符映射到字形索引,这个属性是一个 IDictionary<int, ushort> 结构,其定义如下

    public class GlyphTypeface : ITypefaceMetrics, ISupportInitialize{...public IDictionary<int, ushort> CharacterToGlyphMap{get{CheckInitialized(); // This can only be called on fully initialized GlyphTypefacereturn _fontFace.CharacterMap;}}private FontFaceLayoutInfo          _fontFace;...}

咋看起来没问题,实际调用的时候,通过 CharacterToGlyphMap 的 TryGetValue 方法获取传入的字符对应的字形索引也是十分快速,没有什么耗时。唯独只有调用 CharacterToGlyphMap.Count 属性时,才能测量到很大的耗时

这是为什么呢,让咱继续点开 _fontFace.CharacterMap 属性的定义,其代码如下

    internal sealed class FontFaceLayoutInfo{...internal IntMap CharacterMap{get{return _cmap;}}...}

可见是返回了 IntMap 类型的 _cmap 字段,看到这里,似乎非常清真

继续看看 IntMap 类型的实现

        internal sealed class IntMap : IDictionary<int, ushort>{...public int Count{get { return CMap.Count; }}private Dictionary<int, ushort> CMap{...}...}

看起来其中核心就在于 CMap 的 get 函数里,继续看看此属性的实现

        internal sealed class IntMap : IDictionary<int, ushort>{...private Dictionary<int, ushort> CMap{get{if (_cmap == null){lock (this){if (_cmap == null){_cmap = new Dictionary<int, ushort>();ushort glyphIndex;for (int codePoint = 0; codePoint <= FontFamilyMap.LastUnicodeScalar; ++codePoint){if (TryGetValue(codePoint, out glyphIndex)){_cmap.Add(codePoint, glyphIndex);}}}}}return _cmap;}}private Dictionary<int, ushort>     _cmap;...}public class FontFamilyMap{...internal const int LastUnicodeScalar = 0x10ffff;...}

可以看到,此时如果调用 CharacterToGlyphMap.Count 属性,将会导致 _cmap 字段被初始化。而初始化的过程是采用一个巨大的循环,足足有 0x10ffff 的百万次循环调用 TryGetValue 方法创建的字典

即使 TryGetValue 方法速度再快,但是循环本身将会调用 1114111 (0x10ffff) 百万次,这就是耗时的原因

按照当前的代码,直接调用 CharacterToGlyphMap.Count 属性是非常亏的,将会导致 _cmap 字段,初始化此字典需要经过百万次的循环,自然性能很差。但很显然,这是一个很好做的优化点,只需要绕开字典初始化,直接获取数量即可

既然看起来这是一个很好的优化点,自然我就将其优化了: https://github.com/dotnet/wpf/pull/11139

对于业务端开发者,等不及 WPF 的更新的伙伴们,可以直接使用 GlyphTypeface.GlyphCount 属性代替 CharacterToGlyphMap.Count 属性即可

    public class GlyphTypeface : ITypefaceMetrics, ISupportInitialize{...public int GlyphCount{get{CheckInitialized(); // This can only be called on fully initialized GlyphTypefaceint glyphCount;MS.Internal.Text.TextInterface.FontFace fontFaceDWrite = _font.GetFontFace();try{glyphCount = fontFaceDWrite.GlyphCount;}finally{fontFaceDWrite.Release();}return glyphCount;}}...}

通过以上代码可见 GlyphCount 属性是直接获取的,基本测量不出耗时

博客园博客只做备份,博客发布就不再更新,如果想看最新博客,请访问 https://blog.lindexi.com/

如图片看不见,请在浏览器开启不安全http内容兼容

知识共享许可协议
本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。欢迎转载、使用、重新发布,但务必保留文章署名[林德熙](https://www.cnblogs.com/lindexi)(包含链接:https://www.cnblogs.com/lindexi ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我[联系](mailto:lindexi_gd@163.com)。

相关新闻

  • Java 与智慧交通:车联网与自动驾驶支持
  • 初衷的澄明:空白金兰契的深意
  • Aidoku - 专为iOS/iPadOS打造的免费开源漫画阅读器

最新新闻

  • [Windows]罗技G HUB(Logitech G HUB)旧版本下载地址汇总
  • 电瓶车托运不拆电池行吗?2026新规+省钱方案来了 - 快递物流资讯
  • 2026年北京发电机租赁、应急电源车租赁厂家名单及选购参考指南 - 海棠依旧大
  • 如何配置远程的ubuntu服务器以使在本地windows电脑上可以进行X11图形转发——ssh远程X11转发的配置
  • 电商平台XSS攻击实战防御:从前端到后端的双重安全防线
  • 合肥口碑最好的中专选哪家?综合实力优选合肥理工学校! - 教育为先

日新闻

  • 信任的进化:技术实现详解——如何用JavaScript构建博弈论模拟器
  • Terrakube自定义工作流:如何集成OPA、Infracost等工具扩展IaC能力
  • grunt-concurrent快速入门:5分钟学会并行运行Grunt任务

周新闻

  • 3步解锁iOS设备:applera1n激活锁绕过完全指南
  • 39 2026 人工智能证书终极盘点,普通人选 AI 证书可以从这些方向入手
  • Redis 暴露公网有多危险?从端口检查到补救步骤

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号