完全公开:我正在开发我的libui框架的文本API。这在Windows上封装了DirectWrite,在OS上封装了核心文本,在其他Unixes上封装了Pango (使用HarfBuzz进行OpenType成形)。我要指定的文本格式属性之一是要使用的OpenType特性的集合,这三个特性都提供了;DirectWrite的属性是IDWriteTypography。
现在,当您使用这些库绘制一些文本时,默认情况下您将获得一些有用的OpenType特性,比如标准连接(liga),比如f+i连接。我认为这是特定于字体的,但事实证明,这是特定于文本的脚本正在形成。微软为OpenType支持的所有脚本提供了指导方针。 (在“特定于脚本的开发”下),我可以看到在HarfBuzz本身中进行这一切以确认它的复杂逻辑。
在Core Text和Pango上,如果我启用其他属性,它们将被添加到这些缺省值之上。但是使用DirectWrite,特别是IDWriteTextLayout::SetTypography(),这样做可以消除缺省值。

生成此输出的程序可以找到这里。
显然,我的第一个选择是询问如何在DirectWrite上获得默认特性。不过,有人已经在这个网站上这么做了,答案似乎是“不”。
我猜想DirectWrite允许我完全控制应用于某些文本的特性列表。这很好,除非我显式地禁用了默认特性,否则我不能在其他API中做到这一点!当然,我不知道这个列表是否会改变,所以硬编码可能不是最好的主意。
即使硬编码是一种选择,我也可以为每个脚本获取HarfBuzz的列表,但是( a) 这相当复杂 b)一个脚本有多个可能的塑造器,这取决于(我认为)版本兼容性(例如缅甸)。
那么,为什么不使用HarfBuzz的列表来重新创建DirectWrite的默认特性列表呢?它似乎想要准确的其他形状无论如何,所以这应该是可行的,对吗?我需要做两件事:找出要使用哪个脚本,以及在哪个字符上使用哪个字符,其中字符在单词中的位置很重要。
DirectWrite提供了一个接口IDWriteTextAnalyzer,它提供了执行成形的工具。我可以使用它,但是脚本数据似乎是在一个结构中返回的,对脚本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呢?好的,类型的文档说它的脚本ID是一个“不透明的值”,“这个成员的值是未定义的,应用程序不应该依赖于它的值从一个版本到下一个版本是相同的”。虽然我可以获得一个语言代码来识别脚本,但除了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提供了一个与Direct2D非常相似的绘制2D图形的API,并填补了许多漏洞,我不得不手工编写大量胶水代码来使用普通的Direct2D来完成相同的事情,所以我假设XAML中的任何东西都可以用Direct2D实现,而且扩展到DirectWrite,因为它们是在技术上一起引入的……)
在这一点上我完全迷路了。我希望至少在不同的平台上都是可预测的,而且我也不确定程序应该如何直接或不直接地使用OpenType特性,更不用说了。我是不是对文本布局API产生了不好的期望?如果我想要这样做的话,我必须放弃IDWriteTextLayout,自己做所有的文本整形和布局吗?
还是我必须放弃普通的Windows 7支持并升级到Platform Update DirectWrite功能集?甚至是Windows 7呢?
发布于 2017-07-23 16:53:13
在与Peter和Ebrahim Byagowi进行了一些讨论之后,我去调试了一个更通用的程序,我快速地构建了一个程序来测试这些东西,并且我了解了内部发生了什么。
然而,首先,我要说--这同样适用于Uniscribe和DirectWrite --。
事实证明,DirectWrite总是提供一组默认的OpenType特性,不管我使用的是什么特性集!情况是,根据是否加载自己的特性和整形引擎,所提供的默认功能列表不同。对于水平编写模式的latn脚本和英语,这是通过“泛型引擎”完成的。
如果我不提供任何功能,通用引擎将加载脚本特定的功能。对于水平latn,此列表为
locl
ccmp
rlig
rclt
calt
liga
clig如果我确实提供了特性,泛型引擎将对所有脚本使用相同的默认列表:
locl
ccmp
rclt
rlig
mark
mkmk
dist所以我不知道该怎么办。我也许可以自己用libui代码(当然标记为liga )来提供HACK和其他一些代码,但这仍然很奇怪。我也不知道动机是什么。不管怎样,这解释了我所看到的行为。
发布于 2018-02-19 10:57:43
如果你的问题一般是关于编程的,或者至少是关于编程的,我会试着回答你的一些疑问句。
如果我想在缺省值的基础上添加排印功能,那么我必须在代码中完全放弃使用IDWriteTextLayout吗?
那得看情况。如果IDWriteTextLayout接口在所有方面都很适合您的项目任务,除了DirectWrite默认排版功能的易变性外,了解如何处理排版,并创建一个适合您的需要的IDWriteTypography实例。为程序开发自定义文本布局可能需要大量的时间和精力,特别是如果程序应该呈现双向文本、复杂脚本、内联对象等。
可能会发生这样的情况:项目的任务需要开发一个文本布局引擎,其原因不仅仅是为了控制渲染文本中使用的排印功能。例如,您的经理/客户可能要求实现定制的分行机会或字形预先调整算法。在这个场景中,您将实现一个IDWriteTextAnalizer::GetGlyphs方法。此方法具有参数DWRITE_TYPOGRAPHIC_FEATURES ** features、const UINT32 * featureRangeLengths、UINT32 featureRanges,并且该参数使您能够为要呈现的文本范围替换一组“默认”排版功能(请参阅我对另一个问题IDWriteTextLayout使用的默认排版设置是什么?的回答)。只有受影响的功能才会被修改;其他功能有它们的“默认值”。此外,如果您在下一个文本范围的GetGlyphs调用中省略了这个参数(例如,使用NULL、NULL、0),那么上一个GetGlyphs调用中更改的特性将不会被下一个范围的调用所更改。
等效SCRIPT_ANALYSIS类型的文档表明,它的脚本ID是一个“不透明值”,“该成员的值是未定义的,应用程序不应该依赖于其值从一个版本到下一个版本是相同的”。虽然我可以获得一个语言代码来识别脚本,但除了LANG_ENGLISH (拉丁文?),仍然没有其他定义的值。脚本。
严格地说,这不是一个疑问语句,但我想您不满意这些Unicode脚本ID是如何定义的,以及如何使用定义如此模糊的结构和常量的API。
它可能不是主题,但我有风险假设"Unicode脚本ID“值的来源。截至2010-07-17年,Unicode公司发布了Unicode 6.0版本.该标准包含文档http://www.unicode.org/Public/6.0.0/ucd/PropertyValueAliases.txt,其中一个部分包含一个脚本列表。清单是这样写的:
# Script (sc)
sc ; Arab ; Arabic
sc ; Armi ; Imperial_Aramaic
etc.阿拉伯脚本是#1,西里尔字母是#20,拉丁脚本在这个列表中是#47。此外,在其他地方,我看到了这个列表,从脚本公共和继承开始。它把阿拉伯文字放在第3位,西里尔字母放在第22位,拉丁文放在第49位。这些序号你很熟悉,不是吗?
幸运的是,我们不需要依赖"Unicode脚本ID“值;我们需要脚本属性,而不是脚本ID或缩写。API是自洽的,因为它为文本范围提供了实际的脚本属性,当我们将从GetScriptProperties调用派生出来的数字传递给AnalyzeScript方法时。
https://stackoverflow.com/questions/44611592
复制相似问题