全面披露:我正在开发我的libui GUI框架的文本API。这个API在Windows上使用DirectWrite,在OS X上使用Core Text,在其他Unix系统上使用Pango(它使用HarfBuzz进行OpenType shaping)。我想指定的文本格式属性之一是要使用的一组OpenType特性,这三个库都提供;DirectWrite的是IDWriteTypography。
现在,当你使用这些库绘制一些文本时,默认情况下会启用一些有用的OpenType特性,例如标准连字(如f+i连字)的liga。我以为这是特定于字体的,但事实证明这是特定于正在被塑造的文本的脚本。Microsoft为OpenType支持的所有脚本提供了指导方针(在“特定于脚本的开发”下),我可以看到在HarfBuzz中执行所有这些操作的相当复杂的逻辑。
在Core Text和Pango中,如果我启用其他属性,它们将添加到这些默认值之上。但是在DirectWrite中,特别是IDWriteTextLayout::SetTypography(),这样做会删除默认值:
生成此输出的程序可以在此处找到。
显然,我的第一个选择是询问如何在DirectWrite中获取默认特性。尽管已经有人在这个网站上这样做了,但答案似乎是否定的。
我猜DirectWrite允许我完全控制要应用于某些文本的特性列表。这很好,除了我不能在其他API中这样做,除非我以某种方式明确禁用默认功能!当然,我不知道这个列表是否会改变,所以硬编码可能不是最好的主意。
即使硬编码是一个选择,我也可以获取每个脚本的HarfBuzz列表,但是a)它相当复杂;b)对于一个脚本,有多个可能的shaper,取决于(我认为)版本兼容性(例如,缅甸)。
那么为什么不使用HarfBuzz的列表重新创建DirectWrite的默认特征列表呢?毕竟,它似乎想要对其他字形生成器精确,所以这应该可行,不是吗?好的,我需要做两件事情:确定要使用哪个脚本,并确定在其中的哪些字符上使用哪些属性,以使字符在单词中的位置很重要。
DirectWrite提供了一个接口IDWriteTextAnalyzer,提供执行字形处理的功能。我可以使用它,但是它似乎返回脚本数据在DWRITE_SCRIPT_ANALYSIS结构中,而脚本ID的描述说“写作系统脚本的从零开始的索引表示”。这并没有帮助,所以我编写了一个程序来仅转储我输入的文本的脚本编号。在输入字符串上运行它。
产生输出
我无法将这些脚本编号与任何Windows头文件中的内容匹配:如果在任何API中定义了阿拉伯语、拉丁语或西里尔语的编号,它们都不匹配这些编号。即使我得到了脚本和脚本编号之间的映射,这仍然不能为我提供应用单词内部特征所需的数据。
那么Uniscribe呢?其等效的SCRIPT_ANALYSIS类型的文档表明,它的脚本ID是一个“[opaque]值”,其“该成员的值是未定义的,应用程序不应依赖其值从一个释放版本到下一个版本的值相同”。虽然我可以通过语言代码来确定脚本,但除了“西方”(拉丁文?)脚本的LANG_ENGLISH外,还没有定义的值。DirectWrite的值是否与Uniscribe的值相同?而且看起来我至少可以通过查看fLinkBefore和fLinkAfter字段来确定单词的初始和最终状态,但这是否足以正确地应用每个脚本的属性?
HarfBuzz确实有一个实验性的DirectWrite后端,并且不打算被真正的程序使用;我还不确定它是否具有我上面指定的相同特性破坏。如果我找出来了,我会在这里更新这部分。
最后,如果我在类似kaxaml的东西中输入以下等效测试用例:
我看到连字符被正确应用,即使在后一种情况下:
(结尾的分数只是为了证明那个属性被应用了。)如果我假设XAML使用DirectWrite,则证明我的第一个选项(简单地将自定义属性覆盖在默认属性上)应该是可行的...(我基于这样的想法做出这个假设:XAML提供了一个非常相似的API来绘制2D图形,与我必须手动编写大量粘合代码来使用vanilla Direct2D做相同的事情相比,在XAML中有很多填补的空缺,因此我认为在XAML中可能的任何事情都可能在Direct2D中实现,并且通过扩展DirectWrite也可以实现,因为它们在技术上是同时引入的...)
此时我完全迷失了。我希望至少在各平台上能够预测,但我不确定程序甚至是否应直接使用OpenType功能。我对文本布局API有错误的期望吗?如果我想要这个,我是否必须放弃IDWriteTextLayout并自己完成所有文本成形和布局?
还是说我必须放弃普通的Windows 7支持并升级到平台更新的DirectWrite功能集?甚至放弃Windows 7?
现在,当你使用这些库绘制一些文本时,默认情况下会启用一些有用的OpenType特性,例如标准连字(如f+i连字)的liga。我以为这是特定于字体的,但事实证明这是特定于正在被塑造的文本的脚本。Microsoft为OpenType支持的所有脚本提供了指导方针(在“特定于脚本的开发”下),我可以看到在HarfBuzz中执行所有这些操作的相当复杂的逻辑。
在Core Text和Pango中,如果我启用其他属性,它们将添加到这些默认值之上。但是在DirectWrite中,特别是IDWriteTextLayout::SetTypography(),这样做会删除默认值:
生成此输出的程序可以在此处找到。
显然,我的第一个选择是询问如何在DirectWrite中获取默认特性。尽管已经有人在这个网站上这样做了,但答案似乎是否定的。
我猜DirectWrite允许我完全控制要应用于某些文本的特性列表。这很好,除了我不能在其他API中这样做,除非我以某种方式明确禁用默认功能!当然,我不知道这个列表是否会改变,所以硬编码可能不是最好的主意。
即使硬编码是一个选择,我也可以获取每个脚本的HarfBuzz列表,但是a)它相当复杂;b)对于一个脚本,有多个可能的shaper,取决于(我认为)版本兼容性(例如,缅甸)。
那么为什么不使用HarfBuzz的列表重新创建DirectWrite的默认特征列表呢?毕竟,它似乎想要对其他字形生成器精确,所以这应该可行,不是吗?好的,我需要做两件事情:确定要使用哪个脚本,并确定在其中的哪些字符上使用哪些属性,以使字符在单词中的位置很重要。
DirectWrite提供了一个接口IDWriteTextAnalyzer,提供执行字形处理的功能。我可以使用它,但是它似乎返回脚本数据在DWRITE_SCRIPT_ANALYSIS结构中,而脚本ID的描述说“写作系统脚本的从零开始的索引表示”。这并没有帮助,所以我编写了一个程序来仅转储我输入的文本的脚本编号。在输入字符串上运行它。
لللللللللللللاااااااااالا abcd محمد ابن بطوطة Отложения датского яруса
产生输出
0 - 26 script 3 shapes 0
26 - 5 script 49 shapes 0
31 - 14 script 3 shapes 0
45 - 2 script 1 shapes 1
47 - 25 script 22 shapes 0
我无法将这些脚本编号与任何Windows头文件中的内容匹配:如果在任何API中定义了阿拉伯语、拉丁语或西里尔语的编号,它们都不匹配这些编号。即使我得到了脚本和脚本编号之间的映射,这仍然不能为我提供应用单词内部特征所需的数据。
那么Uniscribe呢?其等效的SCRIPT_ANALYSIS类型的文档表明,它的脚本ID是一个“[opaque]值”,其“该成员的值是未定义的,应用程序不应依赖其值从一个释放版本到下一个版本的值相同”。虽然我可以通过语言代码来确定脚本,但除了“西方”(拉丁文?)脚本的LANG_ENGLISH外,还没有定义的值。DirectWrite的值是否与Uniscribe的值相同?而且看起来我至少可以通过查看fLinkBefore和fLinkAfter字段来确定单词的初始和最终状态,但这是否足以正确地应用每个脚本的属性?
HarfBuzz确实有一个实验性的DirectWrite后端,并且不打算被真正的程序使用;我还不确定它是否具有我上面指定的相同特性破坏。如果我找出来了,我会在这里更新这部分。
最后,如果我在类似kaxaml的东西中输入以下等效测试用例:
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<FlowDocumentPageViewer>
<FlowDocument FontFamily="Constantia" FontSize="48">
<Paragraph>
afford afire aflight 1/4<LineBreak/>
<Run Typography.Fraction="1">afford afire aflight 1/4</Run>
</Paragraph>
</FlowDocument>
</FlowDocumentPageViewer>
</Grid>
</Page>
我看到连字符被正确应用,即使在后一种情况下:
(结尾的分数只是为了证明那个属性被应用了。)如果我假设XAML使用DirectWrite,则证明我的第一个选项(简单地将自定义属性覆盖在默认属性上)应该是可行的...(我基于这样的想法做出这个假设:XAML提供了一个非常相似的API来绘制2D图形,与我必须手动编写大量粘合代码来使用vanilla Direct2D做相同的事情相比,在XAML中有很多填补的空缺,因此我认为在XAML中可能的任何事情都可能在Direct2D中实现,并且通过扩展DirectWrite也可以实现,因为它们在技术上是同时引入的...)
此时我完全迷失了。我希望至少在各平台上能够预测,但我不确定程序甚至是否应直接使用OpenType功能。我对文本布局API有错误的期望吗?如果我想要这个,我是否必须放弃IDWriteTextLayout并自己完成所有文本成形和布局?
还是说我必须放弃普通的Windows 7支持并升级到平台更新的DirectWrite功能集?甚至放弃Windows 7?
GetScriptProperties()
是在IDWriteTextAnalyzer1中新增的,我可以使用它来猜测哪些脚本得到了什么,但我可以使用Uniscribe的ScriptItemizeOpenType()
并获取OpenType脚本标记而不是ISO脚本代码,这可能会使它变得更容易...我将在明天更新的问题中写更多内容。 - andlabs