如何使用DirectWrite在面向脚本的OpenType功能与其他OpenType功能之间取得平衡? [英] How do I balance script-oriented OpenType features with other OpenType features using DirectWrite?

查看:134
本文介绍了如何使用DirectWrite在面向脚本的OpenType功能与其他OpenType功能之间取得平衡?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

全面披露:我正在研究我的libui GUI框架的文本API.这将在Windows上包装DirectWrite,在OS X上包装Core Text,在其他Unix上包装Pango(使用HarfBuzz进行OpenType成形).我要指定的文本格式属性之一是要使用的OpenType功能的集合,这三个功能都可以提供; DirectWrite的是IDWriteTypography.

Full disclosure: I'm working on my libui GUI framework's text API. This wraps DirectWrite on Windows, Core Text on OS X, and Pango (which uses HarfBuzz for OpenType shaping) on other Unixes. One of the text formatting attributes I want to specify is a collection of OpenType features to use, which all three provide; DirectWrite's is IDWriteTypography.

现在,当您使用这些库绘制一些文本时,默认情况下,您将启用一些有用的OpenType功能,例如f + i连字之类的标准连字(liga).我以为这是特定于字体的,但事实证明,这是特定于所成形文本的脚本的. Microsoft为OpenType支持的所有脚本提供了指南(在脚本-具体开发"),我可以在HarfBuzz本身中看到相当复杂的逻辑来进行确认.

Now, when you draw some text with these libraries, by default you'll get a few useful OpenType features enabled, such as the standard ligatures (liga) like the f+i ligature. I thought this was font-specific, but it turns out this is specific to the script of the text being shaped. Microsoft provides guidelines for all the scripts supported by OpenType (under "Script-specific Development"), and I can see rather complex logic for doing it all in HarfBuzz itself to confirm it.

在Core Text和Pango上,如果启用其他属性,则会将它们添加到这些默认值的顶部.但是使用DirectWrite(尤其是IDWriteTextLayout::SetTypography()),这样做会删除默认设置:

On Core Text and Pango, if I enable other attributes, they'll be added on top of these defaults. But with DirectWrite, in particular IDWriteTextLayout::SetTypography(), doing so removes the defaults:

可以在此处找到产生此输出的程序.

The program that produces this output is can be found here.

很明显,我的第一个选择是询问如何在DirectWrite上获取默认功能. 在此网站上已经有人这样做了,答案似乎成为否".

Obviously my first option would be to ask how to get the default features on DirectWrite. Someone did so already on this site, though, and the answer seems to be "no".

我猜想DirectWrite允许我完全控制要应用于某些文本的功能列表.很好,除了我不能用其他API做到这一点,除非我以某种方式显式禁用了默认功能!当然,我不知道此列表是否会更改,因此对其进行硬编码可能不是最好的主意.

I am guessing that DirectWrite is allowing me to be in complete control of the list of features to apply to some text. This is nice, except that I can't do this with the other APIs unless I explicitly disable the default features somehow! Of course, I don't know if this list will ever change, so hardcoding it might not be the best idea.

即使可以选择使用硬编码,我也可以获取每个脚本的HarfBuzz列表,但是a)

Even if hardcoding is an option, I could just grab HarfBuzz's list for each script, but a) it's rather complicated b) there are multiple possible shapers for a script, depending on (I think) version compatibility (for instance, Myanmar).

那么,为什么不使用HarfBuzz的列表来为DirectWrite重新创建默认的功能列表呢?无论如何,它似乎仍想对其他成型者精确,所以这应该可行,对吗?好吧,我需要做两件事:找出要使用的脚本,并找出要在脚本的哪些字符上使用哪些属性,其中字符在单词中的位置很重要.

So why not use HarfBuzz's lists to recreate the default list of features for DirectWrite anyway? It seems to want to be accurate to other shapers anyway, so this should work, right? Well I would need to do two things: figure out what script to use, and figure out which attributes to use on which characters for script where the position of a character in the word matters.

DirectWrite提供接口IDWriteTextAnalyzer,该接口提供执行整形的功能.我可以使用它,但是脚本数据似乎在 DWRITE_SCRIPT_ANALYSIS结构,脚本ID的描述为编写系统脚本的从零开始的索引表示.".

DirectWrite provides an interface IDWriteTextAnalyzer that provides facilities to perform shaping. I could use this, but it seems the script data is returned in a DWRITE_SCRIPT_ANALYSIS structure, and the description for the script ID says "The zero-based index representation of writing system script.".

这没有帮助,所以我写了一个仅转储脚本的程序我输入的文字的数字.在输入字符串上运行

This doesn't help, so I wrote a program to just dump the script numbers for text I type in. Running it on the input string

لللللللللللللاااااااااالا 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中都为阿拉伯文,拉丁文或西里尔文定义了编号,则它们不匹配.即使我确实获得了脚本和脚本编号之间的映射,但这仍然无法为我提供应用词内功能的数据.

I cannot match these script numbers to anything in any of the Windows headers: if there is a defined number for Arabic, Latin, or Cyrillic in any API, they don't match these. And even if I did get a mapping between script and script number, that still doesn't give me the data to apply intra-word features.

Uniscribe怎么样?好吧,等效SCRIPT_ANALYSIS type 表示其脚本ID是"[opaque]值",其此成员的值未定义,应用程序不应依赖于其值在一个发行版与下一个发行版中相同".虽然我可以通过 语言代码来识别脚本,但对于西方"(拉丁语)脚本,除了LANG_ENGLISH之外,没有定义的值. DirectWrite值与Uniscribe值相同吗?看来我至少可以通过查看fLinkBeforefLinkAfter字段来了解单词的初始状态和最终状态,但这是否足以正确地按脚本应用属性?

What about Uniscribe? Well, the documentation for the equivalent SCRIPT_ANALYSIS type says that its script ID is an "[opaque] value" whose "value for this member is undefined and applications should not rely on its value being the same from one release to the next". And while I can get a language code to identify the script by, there's still no defined value other than LANG_ENGLISH for "Western" (Latin?) scripts. Are the DirectWrite values the same as the Uniscribe ones? And it seems like I can at least figure the initial and final states of words by looking at the fLinkBefore and fLinkAfter fields, but is this enough to properly apply attributes per-script?

HarfBuzz确实有一个实验性DirectWrite后端,不打算由真实程序;我尚不确定它是否具有与上面指定的功能相同的功能.如果发现了,我将在这里更新此部分.

HarfBuzz does have an experimental DirectWrite backend that isn't intended to be used by real programs; I'm not yet sure whether it has the same feature-clobbering I specified above. If I find out, I'll update this part here.

最后,如果我以类似kaxaml的形式输入以下与第一个用例相同的测试用例:

Finally, if I enter the following equivalent test case to the first one above in something like 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>

即使在后一种情况下,我也可以正确应用连字:

I see the ligatures being applied properly, even in the latter case:

(最后的部分只是为了证明正在应用那个属性.)如果我假设XAML使用DirectWrite,那么这证明了我的第一个选择(只需将自定义属性覆盖在应该是可能的...(我基于XAML提供了与Direct2D极为相似的API来绘制2D图形的想法,并以此为基础进行了这样的假设,手动编写大量胶水代码以使用香草Direct2D进行相同的操作,因此我假设Direct2D可以实现XAML中的所有功能,并且通过扩展DirectWrite可以实现,因为它们是在技术上一起引入的...)

(The fraction at the end is just to prove that that attribute is being applied.) If I assume XAML uses DirectWrite, then that proves my first option (simply overlaying my custom attributes on top of the defaults) should be possible... (I make this assumption based on the idea that XAML provides a strikingly similar API to Direct2D for drawing 2D graphics, and has a lot of holes filled in where I had to manually write a lot of glue code to do the same things with vanilla Direct2D, so I assume whatever is possible in XAML is possible with Direct2D, and by extension DirectWrite since they were technically introduced together...)

这时我完全迷路了.我至少希望跨平台可预测,而且我不确定程序应如何直接使用OpenType功能,更不用说如何使用OpenType功能了.我对文本布局API的期望不高吗?如果需要的话,我是否必须删除IDWriteTextLayout并自行完成所有文本的变形和布局?

At this point I'm completely lost. I want to at least be predictable across platforms, and I'm not sure how programs are even supposed to, let alone going to, use OpenType features directly or not anyway. Am I making bad expectations of text layout APIs? Will I have to drop IDWriteTextLayout and do all the text shaping and layout myself if I want this?

还是我必须放弃对Windows 7的支持并升级到Platform Update DirectWrite功能集?甚至完全是Windows 7?

Or do I have to drop vanilla Windows 7 support and upgrade to the Platform Update DirectWrite feature set? Or even Windows 7 entirely?

推荐答案

在与Peter Sikking和Ebrahim Byagowi进行了一些讨论之后,我去调试了一个我快速构建的通用程序来测试事物,并且弄清楚了要做什么.在内部.

After some discussions with Peter Sikking and Ebrahim Byagowi, I went and debugged a more general-purpose program I built quickly to test things, and I figured out what's going on internally.

但是,首先,我会说这同样适用于Uniscribe和DirectWrite .

事实证明,无论我使用哪种功能,DirectWrite始终提供一组默认的OpenType功能!情况是,所提供的默认功能的列表会有所不同,具体取决于我是否加载自己的功能以及整形引擎.对于水平书写模式下的latn脚本和英语而言,这是通过通用引擎"完成的.

As it turns out, DirectWrite is always providing a set of default OpenType features, regardless of what feature set I use! The situation is that the list of default features provided differs depending on whether I load my own features or not, and depending on the shaping engine. For the latn script in horizontal writing mode and for English, this is done with the "generic engine".

如果我不提供任何功能,则通用引擎将加载特定于脚本的功能.对于水平latn,此列表为

If I don't provide any features, the generic engine will load script-specific features. For horizontal latn, this list is

locl
ccmp
rlig
rclt
calt
liga
clig

如果我确实提供功能,则通用引擎将对所有脚本使用相同的默认列表:

If I do provide features, the generic engine will use the same default list for all scripts:

locl
ccmp
rclt
rlig
mark
mkmk
dist

所以我不知道该怎么办.我可能可以在libui代码中自己提供liga和其他一些代码(当然标记为HACK),但这仍然很奇怪.我不确定动机是什么.无论哪种方式,这都可以解释我所看到的行为.

So I don't know what to do about this. I could probably just provide liga and a few others myself in libui code (marked as a HACK of course), but this is still weird. I'm not sure what the motivation is either. Either way, this explains the behavior I'm seeing.

这篇关于如何使用DirectWrite在面向脚本的OpenType功能与其他OpenType功能之间取得平衡?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆