Skip to content

dotnet 读 WPF 源代码笔记 聊聊 OpenType 定义的字体特性

Updated: at 06:58,Created: at 00:49

本文记录我读 WPF 源代码的 OpenType 字体特性标签 OpenType Feature Tags 的笔记内容

本文部分内容由 AI 辅助记录和整理

在 WPF 里面,关于 Feature Tag 字体特性的定义是放在 src\Microsoft.DotNet.Wpf\src\PresentationCore\MS\Internal\FontFace\Tags.cs 文件里面,定义的枚举代码内容如下

internal enum FeatureTags
{
AccessAllAlternates = 0x61616c74, // 'aalt'
AboveBaseForms = 0x61627666, // 'abvf'
AboveBaseMarkPositioning = 0x6162766d, // 'abvm'
AboveBaseSubstitutions = 0x61627673, // 'abvs'
AlternativeFractions = 0x61667263, // 'afrc'
Akhands = 0x616b686e, // 'akhn'
BelowBaseForms = 0x626c7766, // 'blwf'
BelowBaseMarkPositioning = 0x626c776d, // 'blwm'
BelowBaseSubstitutions = 0x626c7773, // 'blws'
PetiteCapitalsFromCapitals = 0x63327063, // 'c2pc'
SmallCapitalsFromCapitals = 0x63327363, // 'c2sc'
ContextualAlternates = 0x63616c74, // 'calt'
CaseSensitiveForms = 0x63617365, // 'case'
GlyphCompositionDecomposition = 0x63636d70, // 'ccmp'
Conjunctformafterro = 0x63666172, // 'cfar'
ContextualLigatures = 0x636c6967, // 'clig'
Conjuncts = 0x636a6374, // 'cjct'
CapitalSpacing = 0x63707370, // 'cpsp'
ContextualSwash = 0x63737768, // 'cswh'
CursivePositioning = 0x63757273, // 'curs'
DefaultProcessing = 0x64666c74, // 'dflt'
Distances = 0x64697374, // 'dist'
DiscretionaryLigatures = 0x646c6967, // 'dlig'
Denominators = 0x646e6f6d, // 'dnom'
Diphthongs = 0x64706e67, // 'dpng'
ExpertForms = 0x65787074, // 'expt'
FinalglyphAlternates = 0x66616c74, // 'falt'
TerminalForms = 0x66696e61, // 'fina'
TerminalForms2 = 0x66696e32, // 'fin2'
TerminalForms3 = 0x66696e33, // 'fin3'
Fractions = 0x66726163, // 'frac'
FullWidth = 0x66776964, // 'fwid'
HalfForms = 0x68616c66, // 'half'
HalantForms = 0x68616c6e, // 'haln'
AlternateHalfWidth = 0x68616c74, // 'halt'
HistoricalForms = 0x68697374, // 'hist'
HorizontalKanaAlternates = 0x686b6e61, // 'hkna'
HistoricalLigatures = 0x686c6967, // 'hlig'
Hangul = 0x686e676c, // 'hngl'
HalfWidth = 0x68776964, // 'hwid'
HojoKanjiForms = 0x686f6a6f, // 'hojo'
InitialForms = 0x696e6974, // 'init'
IsolatedForms = 0x69736f6c, // 'isol'
Italics = 0x6974616c, // 'ital'
JapaneseForms = 0x6a616a70, // 'jajp'
JustificationAlternatives = 0x6a616c74, // 'jalt'
JIS04Forms = 0x6a703034, // 'jp04'
JIS78Forms = 0x6a703738, // 'jp78'
JIS83Forms = 0x6a703833, // 'jp83'
JIS90Forms = 0x6a703930, // 'jp90'
Kerning = 0x6b65726e, // 'kern'
LeftBounds = 0x6c666264, // 'lfbd'
StandardLigatures = 0x6c696761, // 'liga'
LeadingJamoForms = 0x6c6a6d6f, // 'ljmo'
LiningFigures = 0x6c6e756d, // 'lnum'
LocalizedForms = 0x6c6f636c, // 'locl'
MarkPositioning = 0x6d61726b, // 'mark'
MedialForms = 0x6d656469, // 'medi'
MedialForms2 = 0x6d656432, // 'med2'
MathematicalGreek = 0x6d67726b, // 'mgrk'
MarktoMarkPositioning = 0x6d6b6d6b, // 'mkmk'
MarkPositioningviaSubstitution = 0x6d736574, // 'mset'
AlternateAnnotationForms = 0x6e616c74, // 'nalt'
NLCKanjiForms = 0x6e6c636b, // 'nlck'
NuktaForms = 0x6e756b74, // 'nukt'
Numerators = 0x6e756d72, // 'numr'
OldStyleFigures = 0x6f6e756d, // 'onum'
OpticalBounds = 0x6f706264, // 'opbd'
Ordinals = 0x6f72646e, // 'ordn'
Ornaments = 0x6f726e6d, // 'ornm'
ProportionalAlternateWidth = 0x70616c74, // 'palt'
PetiteCapitals = 0x70636170, // 'pcap'
ProportionalFigures = 0x706e756d, // 'pnum'
PrebaseForms = 0x70726566, // 'pref'
PrebaseSubstitutions = 0x70726573, // 'pres'
PostbaseForms = 0x70737466, // 'pstf'
PostbaseSubstitutions = 0x70737473, // 'psts'
ProportionalWidths = 0x70776964, // 'pwid'
QuarterWidths = 0x71776964, // 'qwid'
Randomize = 0x72616e64, // 'rand'
RakarForms = 0x726b7266, // 'rkrf'
RequiredLigatures = 0x726c6967, // 'rlig'
RephForm = 0x72706866, // 'rphf'
RightBounds = 0x72746264, // 'rtbd'
RightToLeftAlternates = 0x72746c61, // 'rtla'
RubyNotationForms = 0x72756279, // 'ruby'
StylisticAlternates = 0x73616c74, // 'salt'
ScientificInferiors = 0x73696e66, // 'sinf'
OpticalSize = 0x73697a65, // 'size'
SmallCapitals = 0x736d6370, // 'smcp'
SimplifiedForms = 0x736d706c, // 'smpl'
StylisticSet1 = 0x73733031, // 'ss01'
StylisticSet2 = 0x73733032, // 'ss02'
StylisticSet3 = 0x73733033, // 'ss03'
StylisticSet4 = 0x73733034, // 'ss04'
StylisticSet5 = 0x73733035, // 'ss05'
StylisticSet6 = 0x73733036, // 'ss06'
StylisticSet7 = 0x73733037, // 'ss07'
StylisticSet8 = 0x73733038, // 'ss08'
StylisticSet9 = 0x73733039, // 'ss09'
StylisticSet10 = 0x73733130, // 'ss10'
StylisticSet11 = 0x73733131, // 'ss11'
StylisticSet12 = 0x73733132, // 'ss12'
StylisticSet13 = 0x73733133, // 'ss13'
StylisticSet14 = 0x73733134, // 'ss14'
StylisticSet15 = 0x73733135, // 'ss15'
StylisticSet16 = 0x73733136, // 'ss16'
StylisticSet17 = 0x73733137, // 'ss17'
StylisticSet18 = 0x73733138, // 'ss18'
StylisticSet19 = 0x73733139, // 'ss19'
StylisticSet20 = 0x73733230, // 'ss20'
Subscript = 0x73756273, // 'subs'
Superscript = 0x73757073, // 'sups'
Swash = 0x73777368, // 'swsh'
Titling = 0x7469746c, // 'titl'
TrailingJamoForms = 0x746a6d6f, // 'tjmo'
TraditionalNameForms = 0x746e616d, // 'tnam'
TabularFigures = 0x746e756d, // 'tnum'
TraditionalForms = 0x74726164, // 'trad'
ThirdWidths = 0x74776964, // 'twid'
Unicase = 0x756e6963, // 'unic'
AlternateVerticalMetrics = 0x76616c74, // 'valt'
VattuVariants = 0x76617475, // 'vatu'
VerticalWriting = 0x76657274, // 'vert'
AlternateVerticalHalfMetrics = 0x7668616c, // 'vhal'
VowelJamoForms = 0x766a6d6f, // 'vjmo'
VerticalKanaAlternates = 0x766b6e61, // 'vkna'
VerticalKerning = 0x766b726e, // 'vkrn'
ProportionalAlternateVerticalMetrics = 0x7670616c, // 'vpal'
VerticalRotation = 0x76727432, // 'vrt2'
SlashedZero = 0x7a65726f, // 'zero'
}

这个枚举对应的就是 OpenType 规范里定义的字体特性,每个特性都是 4 字符的标签转的整数。在 WPF 代码里面,直接给出的是整数,但在注释里面写明了对应的字符

整个 OpenType 规范里定义的字体特性可以被分为几个大类,比如通用排版、数字相关、大小写相关、连字相关、东亚文字(中日朝、印度文字相关)、特殊字形变体、定位相关这些

首先第一大类:【通用字形变换&定位类】

第二大类:【间距&定位类】

第三大类:【连字(Ligature)类】

第四大类:【数字相关类】

第五大类:【大小写相关类】

第六大类:【东亚文字(中日朝)相关类】

第七大类:【印度系/南亚文字相关类】(这些都是天城文、泰米尔文等南亚文字的专用特性,普通中文排版很少用到)

最后需要说明的是,这些特性大部分都需要字体本身支持才能生效,不是开启了就有用,如果字体没有对应特性的设计,开启了也不会有变化

以下为 AI 整理的表格内容

一、通用排版核心类(最常用)

枚举名标签含义&用途
Kerningkern字距调整,默认开启,优化特定字符对(比如W和a、T和i)的间距,避免空隙过大或重叠
ContextualAlternatescalt上下文替代字形,默认开启,根据相邻字符自动替换字形(比如手写体中同一个字母在词首/词中写法不同)
StandardLigaturesliga标准连字,默认开启,把fi、fl这类容易重叠的字符组合合并成专门设计的连字,提升易读性
GlyphCompositionDecompositionccmp字形组合/分解,基础特性,处理带重音字符、复杂字符的拆分合并,保证文字正确渲染
LocalizedFormslocl本地化字形,根据语言区域自动切换对应字形,比如同一个汉字在大陆/台湾/日本的不同写法、拉丁文的区域变体
CaseSensitiveFormscase大小写敏感适配,全大写排版时自动调整标点、符号的位置,和大写字母对齐更协调
Randomizerand随机字形替换,给同一个字符随机选不同变体,模拟手写的自然错落感,适合艺术字体、手写场景
StylisticAlternatessalt风格替代整组切换,调用字体设计师预设的整套风格化字形,比如统一切换为圆润/尖锐风格
StylisticSet1~20ss01~ss20风格集1-20,字体最多支持20组自定义风格预设,每个集对应一套独立的字形变体,按需切换
Swashswsh花体字,替换为带装饰性的花体字形,多用于西文标题、海报设计
OpticalSizesize光学尺寸适配,根据字号自动调整笔画粗细、间距,小字号更清晰,大字号更美观

二、数字相关类

枚举名标签含义&用途
LiningFigureslnum等高数字,和大写字母高度一致,适合和大写文字混排
OldStyleFiguresonum旧风格/小写数字,有高低错落,和小写字母混排更协调,适合正文排版
ProportionalFigurespnum比例宽度数字,每个数字宽度按形状调整(比如1比8窄),美观性好,适合正文
TabularFigurestnum表格等宽数字,所有数字宽度完全一致,上下对齐整齐,专门用于表格、财务数据、价格显示
Fractionsfrac自动分数渲染,把1/2这类格式直接转成标准分数字形,无需手动调整大小位置
Subscriptsubs自动下标,比如化学公式H₂O的2,无需手动调整字号位置
Superscriptsups自动上标,比如平方米m²的2、注脚标记
Ordinalsordn序数词后缀适配,比如英文1st、2nd里的st/nd自动转为上标形态
SlashedZerozero带斜杠的零,把0显示为带斜杠的样式,避免和字母O混淆,非常适合代码、ID编号、财务场景
Numerators/Denominatorsnumr/dnom分子/分母专属字形,用于复杂分数显示

三、大小写和连字类

枚举名标签含义&用途
SmallCapitalssmcp小型大写字母,把小写字母转成和小写x高度一致的小型大写,比全大写更柔和,适合正文里的缩写
PetiteCapitalspcap超小型大写字母,比小型大写更小,适合精细排版
DiscretionaryLigaturesdlig装饰性连字,默认关闭,启用后显示ff、ffi、st这类艺术化连字,适合设计场景
HistoricalLigatureshlig历史连字,显示古英文、古籍里的古老连字(比如æ、œ)
RequiredLigaturesrlig必需连字,阿拉伯文、希伯来文等文字必须的连字,不开启文字就无法正确显示,渲染引擎默认强制开启
Italicsital原生斜体,切换为字体专门设计的斜体字形,比算法倾斜更美观

四、东亚文字(中日朝)专用类

枚举名标签含义&用途
FullWidth/HalfWidthfwid/hwid全宽/半宽切换,中日韩混排时统一字符宽度,对齐更整齐
VerticalWritingvert竖排适配,切换为竖排专用字形,调整标点、汉字的方向和形状,符合中日韩竖排阅读习惯
VerticalRotationvrt2竖排旋转,把横排的英文、数字自动旋转90度适配竖排文本
RubyNotationFormsruby注音专用字形,专门为日文振假名、中文拼音标注等小字号场景设计,小字号下更清晰
SimplifiedForms/TraditionalFormssmpl/trad简体/繁体字形切换
JIS78/JIS83/JIS90/JIS04jp78~jp04不同年代JIS标准的日文字形切换
HojoKanjiFormshojo日本法务省户籍用汉字字形
Hangul/LeadingJamoForms/VowelJamoForms/TrailingJamoFormshngl/ljmo/vjmo/tjmo谚文(朝鲜语)合成适配,保证谚文的首/中/尾音正确组合显示

五、南亚/RTL文字专用类(普通中文排版很少用到)

这类都是天城文、泰米尔文、阿拉伯文等复杂文字系统的专属特性,用于处理字符的基线上下位置、词首/词中/词尾变体、连字合成: AboveBaseForms/AboveBaseMarkPositioning/AboveBaseSubstitutionsAkhandsBelowBaseForms/BelowBaseMarkPositioning/BelowBaseSubstitutionsConjunctsInitialForms/IsolatedForms/MedialForms/TerminalFormsRakarForms/RephForm/NuktaFormsRightToLeftAlternates等,都是保证复杂文字正确渲染的基础特性。

以上就是我读 WPF 源代码的关于字体特性标签 OpenType Feature Tags 的笔记内容

当前的 WPF 在 https://github.com/dotnet/wpf 完全开源,使用友好的 MIT 协议,意味着允许任何人任何组织和企业任意处置,包括使用,复制,修改,合并,发表,分发,再授权,或者销售。在仓库里面包含了完全的构建逻辑,只需要本地的网络足够好(因为需要下载一堆构建工具),即可进行本地构建


知识共享许可协议

原文链接: http://blog.lindexi.com/post/dotnet-%E8%AF%BB-WPF-%E6%BA%90%E4%BB%A3%E7%A0%81%E7%AC%94%E8%AE%B0-%E8%81%8A%E8%81%8A-OpenType-%E5%AE%9A%E4%B9%89%E7%9A%84%E5%AD%97%E4%BD%93%E7%89%B9%E6%80%A7

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